diff git a/.ackrc b/.ackrc
new file mode 100644
index 0000000000000000000000000000000000000000..74759e641f3594649869c5c11e18a940abbbf0a1
 /dev/null
+++ b/.ackrc
@@ 0,0 +1,6 @@
+# Configuration file for the 'ack' search utility
+# See https://beyondgrep.com/ for details.
+
+# Ignore misc files generated by the build process
+ignorefile=ext:glob,aux
+ignoredir=html
\ No newline at end of file
diff git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..c925e3166ee66e64206fc6ef05efd4bda052ded0
 /dev/null
+++ b/.gitattributes
@@ 0,0 +1 @@
+*.v gitlablanguage=coq
diff git a/.gitignore b/.gitignore
index 0ad4144965651dbfc849d1eaa6acbd42937d7b48..4b9c49399d8139bf1836735005ea66cbeb31c4db 100644
 a/.gitignore
+++ b/.gitignore
@@ 2,6 +2,7 @@
*.glob
*.vo
*.html
+/html
*.aux
Makefile*
_CoqProject
@@ 10,3 +11,7 @@ _CoqProject
*.cache
*~
*.orig
+*/.#*
+#*#
+.#*
+*.DS_Store
\ No newline at end of file
diff git a/.gitlabci.yml b/.gitlabci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1e15747ff708f6368eda20d203184f9914e551ae
 /dev/null
+++ b/.gitlabci.yml
@@ 0,0 +1,78 @@
+stages:
+  build
+  process
+
+.build:
+ stage: build
+ image: mathcomp/mathcomp:${CI_JOB_NAME}
+ script:
+  ./create_makefile.sh
+  make j ${NJOBS}
+
+1.8.0coq8.8:
+ extends: .build
+
+1.9.0coqdev:
+ extends: .build
+ # it's ok to fail with an unreleased version of Coq
+ allow_failure: true
+
+1.9.0coq8.9:
+ extends: .build
+ # Keep track of all compiled output and the build infrastructure
+ artifacts:
+ name: prosabuildfiles
+ paths:
+  _CoqProject
+  Makefile
+  Makefile.conf
+ # Ugly hack around https://gitlab.com/gitlaborg/gitlabrunner/issues/2620
+  "*/*.vo"
+  "*/*/*.vo"
+  "*/*/*/*.vo"
+  "*/*/*/*/*.vo"
+  "*/*/*/*/*/*.vo"
+  "*/*/*/*/*/*/*.vo"
+  "*/*/*/*/*/*/*/*.vo"
+  "*/*/*/*/*/*/*/*/*.vo"
+  "*/*/*/*/*/*/*/*/*/*.vo"
+  "*/*.glob"
+  "*/*/*.glob"
+  "*/*/*/*.glob"
+  "*/*/*/*/*.glob"
+  "*/*/*/*/*/*.glob"
+  "*/*/*/*/*/*/*.glob"
+  "*/*/*/*/*/*/*/*.glob"
+  "*/*/*/*/*/*/*/*/*.glob"
+  "*/*/*/*/*/*/*/*/*/*.glob"
+ expire_in: 1 week
+
+validate:
+ stage: process
+ image: mathcomp/mathcomp:1.9.0coq8.9
+ dependencies:
+  1.9.0coq8.9
+ script: make validate
+
+doc:
+ stage: process
+ image: mathcomp/mathcomp:1.9.0coq8.9
+ dependencies:
+  1.9.0coq8.9
+ script:
+  make html
+  mv html withproofs
+  make gallinahtml
+  mv html withoutproofs
+ artifacts:
+ name: "prosaspec$CI_COMMIT_REF_NAME"
+ paths:
+  "withproofs/"
+  "withoutproofs/"
+ expire_in: 1 week
+
+prooflength:
+ stage: process
+ image: python:3alpine
+ script:
+  scripts/proofloc.py check longproofs scripts/knownlongproofs.json `find . iname *.v`
diff git a/analysis/apa/bertogna_edf_comp.v b/analysis/apa/bertogna_edf_comp.v
index 05b5c8d13cba9216fd5257a9f2647dc033f062d4..b12a361eccb5e5d6b8da80a9c34e2cba630622ae 100755
 a/analysis/apa/bertogna_edf_comp.v
+++ b/analysis/apa/bertogna_edf_comp.v
@@ 972,8 +972,6 @@ Module ResponseTimeIterationEDF.
have COMPLETED := RLIST tsk R HAS j ARRj JOBtsk.
exploit (DL rt_bounds tsk R);
[by ins  by ins  clear DL; intro DL].

 rewrite eqn_leq; apply/andP; split; first by apply cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + R)); last first.
{
unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
@@ 981,8 +979,7 @@ Module ResponseTimeIterationEDF.
specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
by rewrite JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by apply COMPLETED.
+ by done.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/apa/bertogna_edf_theory.v b/analysis/apa/bertogna_edf_theory.v
index 0f032e40fba1a6d4ffe6071dfa371b10164e7dc9..3162a16b563ee6450d3c301e62dd7559c7cadff2 100644
 a/analysis/apa/bertogna_edf_theory.v
+++ b/analysis/apa/bertogna_edf_theory.v
@@ 220,12 +220,12 @@ Module ResponseTimeAnalysisEDF.
Lemma bertogna_edf_specific_bound_holds :
x tsk_other <= edf_specific_bound tsk_other R_other.
Proof.
 apply interference_bound_edf_bounds_interference with (job_deadline0 := job_deadline)
 (arr_seq0 := arr_seq) (ts0 := ts); try (by done);
 [ by apply bertogna_edf_tsk_other_in_ts
  by apply H_tasks_miss_no_deadlines
  by apply H_tasks_miss_no_deadlines  ].
 by ins; apply H_all_previous_jobs_completed_on_time with (tsk_other := tsk_other).
+ apply interference_bound_edf_bounds_interference with
+ (job_deadline0 := job_deadline)
+ (arr_seq0 := arr_seq) (ts0 := ts); try (by done);
+ [ by apply bertogna_edf_tsk_other_in_ts 
+ by apply H_tasks_miss_no_deadlines  ].
+ by ins; apply H_all_previous_jobs_completed_on_time with (tsk_other := tsk_other).
Qed.
End LemmasAboutInterferingTasks.
@@ 246,12 +246,7 @@ Module ResponseTimeAnalysisEDF.
rewrite subh1; last by rewrite [R](REC tsk) // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(job_arrival j <= t < job_arrival j + R)
backlogged job_arrival job_cost sched j t) +
service sched j (job_arrival j + R)); last first.
@@ 357,7 +352,7 @@ Module ResponseTimeAnalysisEDF.
intros t j0 ARR0 LEt LE.
cut ((job_task j0) \in unzip1 rt_bounds = true); last by rewrite UNZIP FROMTS.
move => /mapP [p IN EQ]; destruct p as [tsk' R0]; simpl in *; subst tsk'.
 apply completion_monotonic with (t0 := job_arrival j0 + R0); first by done.
+ apply completion_monotonic with (t0 := job_arrival j0 + R0).
{
rewrite leq_add2l; apply leq_trans with (n := task_deadline (job_task j0));
[by apply NOMISS  by apply CONSTR; rewrite FROMTS].
@@ 976,7 +971,7 @@ Module ResponseTimeAnalysisEDF.
job_task j0 = tsk >
(tsk, R0) \in rt_bounds >
job_arrival j0 + R0 < job_arrival j + R' >
 service sched j0 (job_arrival j0 + R0) == job_cost j0).
+ service sched j0 (job_arrival j0 + R0) >= job_cost j0).
{
by ins; apply IH with (tsk := tsk0) (R := R0).
}
@@ 998,7 +993,7 @@ Module ResponseTimeAnalysisEDF.
unfold interference_bound_edf, interference_bound_generic in LTmin.
rewrite minnAC in LTmin; apply min_lt_same in LTmin.
have BASICBOUND := bertogna_edf_workload_bounds_interference R' j BEFOREok tsk_other R_other HP.
 have EDFBOUND := (bertogna_edf_specific_bound_holds tsk' R' INbounds j ARRj JOBtsk BEFOREok tsk_other R_other HP).
+ have EDFBOUND := (bertogna_edf_specific_bound_holds tsk' R' j ARRj JOBtsk BEFOREok tsk_other R_other HP).
unfold minn in LTmin; clear LTmin HP BASICBOUND EDFBOUND tsk; desf.
{
by apply (leq_ltn_trans BASICBOUND) in LTmin; rewrite ltnn in LTmin.
diff git a/analysis/apa/bertogna_fp_comp.v b/analysis/apa/bertogna_fp_comp.v
index 7c2d76bcbc0a25c4d70b16e1800072ae91d94f3c..2d73ff8321bdc5063faf33cc6a68687c4298183b 100644
 a/analysis/apa/bertogna_fp_comp.v
+++ b/analysis/apa/bertogna_fp_comp.v
@@ 310,7 +310,7 @@ Module ResponseTimeIterationFP.
rename ts into ts'; destruct ts' as [ts UNIQ]; simpl in *.
intros hp_idx idx LThp LT NEQ HP.
rewrite ltn_neqAle; apply/andP; split; first by done.
 by apply sorted_rel_implies_le_idx with (leT := higher_priority) (s := ts) (x0 := elem).
+ by apply sorted_rel_implies_le_idx with (leT := higher_priority) (xs := ts) (default := elem).
Qed.
End HighPriorityTasks.
@@ 696,7 +696,6 @@ Module ResponseTimeIterationFP.
} des.
exploit (RLIST tsk R EX j ARRj); [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 cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + R)); last first.
{
unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
@@ 704,8 +703,7 @@ Module ResponseTimeIterationFP.
specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
by rewrite JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by apply COMPLETED.
+ by done.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/apa/bertogna_fp_theory.v b/analysis/apa/bertogna_fp_theory.v
index 30f4b32860a6aade22adb95f1a732d1be0654a36..76dda042aaf87c897d0909886658067c9bf037b0 100644
 a/analysis/apa/bertogna_fp_theory.v
+++ b/analysis/apa/bertogna_fp_theory.v
@@ 258,12 +258,7 @@ Module ResponseTimeAnalysisFP.
rewrite subh1; last by rewrite [R]REC // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(job_arrival j <= t < job_arrival j + R)
backlogged job_arrival job_cost sched j t) +
service sched j (job_arrival j + R)); last first.
@@ 369,14 +364,10 @@ Module ResponseTimeAnalysisFP.
intros j0 ARR0 INTERF.
exploit (HAS (job_task j0));
[by rewrite FROMTS  by done  move => [R0 INbounds]].
 apply completion_monotonic with (t := job_arrival j0 + R0); first by done.
 {
 rewrite leq_add2l; apply leq_trans with (n := task_deadline (job_task j0));
+ apply completion_monotonic with (t := job_arrival j0 + R0).
+  rewrite leq_add2l; apply leq_trans with (n := task_deadline (job_task j0));
[by apply NOMISS'  by apply CONSTR; rewrite FROMTS].
 }
 {
 by apply (RESP (job_task j0)).
 }
+  by apply (RESP (job_task j0)).
Qed.
(* 3) Next, we prove that the sum of the interference of each task is equal to the
@@ 656,8 +647,7 @@ Module ResponseTimeAnalysisFP.
}
{
intros j0 JOB0 ARR0 LT0.
 apply completion_monotonic with (t0 := job_arrival j0 + R);
 [by done   by apply BEFOREok].
+ apply completion_monotonic with (t0 := job_arrival j0 + R); [ by apply BEFOREok].
by rewrite leq_add2l; apply leq_trans with (n := task_deadline tsk);
last by apply CONSTR; rewrite JOBtsk FROMTS.
}
@@ 1028,7 +1018,7 @@ Module ResponseTimeAnalysisFP.
arrives_in arr_seq j0 >
job_task j0 = tsk >
job_arrival j0 < job_arrival j >
 service sched j0 (job_arrival j0 + R) == job_cost j0).
+ service sched j0 (job_arrival j0 + R) >= job_cost j0).
{
by ins; apply IH; try (by done); rewrite ltn_add2r.
} clear IH.
diff git a/analysis/apa/interference_bound_edf.v b/analysis/apa/interference_bound_edf.v
index 8be9092915391bfe1607f8e058b8daa0d88b850b..76c56e8beda4243a244c68254fdbbef917e1fee8 100644
 a/analysis/apa/interference_bound_edf.v
+++ b/analysis/apa/interference_bound_edf.v
@@ 609,7 +609,7 @@ Module InterferenceBoundEDF.
have FST := interference_bound_edf_j_fst_is_job_of_tsk_k.
destruct FST as [FSTarr [FSTtask [LEdl _]]].
have LTr := interference_bound_edf_response_time_bound_of_j_fst_after_interval.
 apply subh3; last by apply LEdk.
+ apply subh3.
apply leq_trans with (n := job_interference job_arrival job_cost job_task sched alpha j_i j_fst t1
(job_arrival j_fst + R_k) + (D_k  R_k));
first by rewrite leq_add2r; apply extend_sum; [by apply leqnn].
@@ 955,8 +955,8 @@ Module InterferenceBoundEDF.
interference_caused_by j_fst t1 t2 <= D_i %% p_k  (D_k  R_k).
Proof.
intro LE.
 apply subh3; last by apply interference_bound_edf_remainder_ge_slack.
 by rewrite subndiv_eq_mod; apply subh3; last by apply leq_trunc_div.
+ apply subh3.
+ by rewrite subndiv_eq_mod; apply subh3.
Qed.
(* Next, we prove that interference caused by j_fst is bounded by the length
diff git a/analysis/global/basic/bertogna_edf_comp.v b/analysis/global/basic/bertogna_edf_comp.v
index 75d70e96e8b5fba0c9fce449df66f3d004452437..534f815b9ca4b9bccc73dc442c242c2db458b3e0 100755
 a/analysis/global/basic/bertogna_edf_comp.v
+++ b/analysis/global/basic/bertogna_edf_comp.v
@@ 960,8 +960,6 @@ Module ResponseTimeIterationEDF.
exploit (HAS rt_bounds tsk); [by ins  by ins  clear HAS; intro HAS; des].
have COMPLETED := RLIST tsk R HAS j ARRj JOBtsk.
exploit (DL rt_bounds tsk R); try (by done); clear DL; intro DL.

 rewrite eqn_leq; apply/andP; split; first by apply cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + R)); last first.
{
unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
@@ 969,8 +967,7 @@ Module ResponseTimeIterationEDF.
specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
by rewrite JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by apply COMPLETED.
+ by done.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/global/basic/bertogna_edf_theory.v b/analysis/global/basic/bertogna_edf_theory.v
index 484620b75400076f36cf33eec4b80ec161067529..b6bcc8a2b408552fb5ebbe36508f6c2d1d6058ce 100644
 a/analysis/global/basic/bertogna_edf_theory.v
+++ b/analysis/global/basic/bertogna_edf_theory.v
@@ 212,7 +212,7 @@ Module ResponseTimeAnalysisEDF.
(arr_seq0 := arr_seq) (ts0 := ts); try (by done);
[ by apply bertogna_edf_tsk_other_in_ts
 by apply H_tasks_miss_no_deadlines
  by apply H_tasks_miss_no_deadlines  ].
+  ].
by ins; apply H_all_previous_jobs_completed_on_time with (tsk_other := tsk_other).
Qed.
@@ 234,12 +234,7 @@ Module ResponseTimeAnalysisEDF.
rewrite subh1; last by rewrite [R](REC tsk) // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(job_arrival j <= t < job_arrival j + R)
backlogged job_arrival job_cost sched j t) +
service sched j (job_arrival j + R)); last first.
@@ 345,7 +340,7 @@ Module ResponseTimeAnalysisEDF.
intros t j0 ARR0 LEt LE.
cut ((job_task j0) \in unzip1 rt_bounds = true); last by rewrite UNZIP FROMTS.
move => /mapP [p IN EQ]; destruct p as [tsk' R0]; simpl in *; subst tsk'.
 apply completion_monotonic with (t0 := job_arrival j0 + R0); first by done.
+ apply completion_monotonic with (t0 := job_arrival j0 + R0).
{
rewrite leq_add2l; apply leq_trans with (n := task_deadline (job_task j0));
[by apply NOMISS  by apply CONSTR; rewrite FROMTS].
@@ 774,7 +769,7 @@ Module ResponseTimeAnalysisEDF.
job_task j0 = tsk >
(tsk, R0) \in rt_bounds >
job_arrival j0 + R0 < job_arrival j + R' >
 service sched j0 (job_arrival j0 + R0) == job_cost j0).
+ service sched j0 (job_arrival j0 + R0) >= job_cost j0).
{
by ins; apply IH with (tsk := tsk0) (R := R0).
}
@@ 796,7 +791,7 @@ Module ResponseTimeAnalysisEDF.
unfold interference_bound_edf, interference_bound_generic in LTmin.
rewrite minnAC in LTmin; apply min_lt_same in LTmin.
have BASICBOUND := bertogna_edf_workload_bounds_interference R' j BEFOREok tsk_other R_other HP.
 have EDFBOUND := (bertogna_edf_specific_bound_holds tsk' R' INbounds j ARRj
+ have EDFBOUND := (bertogna_edf_specific_bound_holds tsk' R' j ARRj
JOBtsk BEFOREok tsk_other R_other HP).
unfold minn in LTmin; clear LTmin HP BASICBOUND EDFBOUND tsk; desf.
{
diff git a/analysis/global/basic/bertogna_fp_comp.v b/analysis/global/basic/bertogna_fp_comp.v
index 920d9dff0898639796dcfec1264248035478ebec..4f7af25d41fc1f459be455d72b33d4e4f288ac34 100644
 a/analysis/global/basic/bertogna_fp_comp.v
+++ b/analysis/global/basic/bertogna_fp_comp.v
@@ 304,7 +304,7 @@ Module ResponseTimeIterationFP.
rename ts into ts'; destruct ts' as [ts UNIQ]; simpl in *.
intros hp_idx idx LThp LT NEQ HP.
rewrite ltn_neqAle; apply/andP; split; first by done.
 by apply sorted_rel_implies_le_idx with (leT := higher_priority) (s := ts) (x0 := elem).
+ by apply sorted_rel_implies_le_idx with (leT := higher_priority) (xs := ts) (default := elem).
Qed.
End HighPriorityTasks.
@@ 679,16 +679,11 @@ Module ResponseTimeIterationFP.
} des.
exploit (RLIST tsk R EX j ARRj); [by done  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 cumulative_service_le_job_cost.
 apply leq_trans with (n := service sched j (job_arrival j + R)); last first.
 {
 unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
 apply extend_sum; rewrite // leq_add2l.
 specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
+ apply leq_trans with (n := service sched j (job_arrival j + R)); first by done.
+ unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
+ apply extend_sum; rewrite // leq_add2l.
+ specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
by rewrite JOBtsk.
 }
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by apply COMPLETED.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/global/basic/bertogna_fp_theory.v b/analysis/global/basic/bertogna_fp_theory.v
index 4091fe058707f0274717e8908aab3ae32b8cca79..bd4c074f074d2d757e2f1c86cb941b057ddfb56e 100644
 a/analysis/global/basic/bertogna_fp_theory.v
+++ b/analysis/global/basic/bertogna_fp_theory.v
@@ 242,12 +242,7 @@ Module ResponseTimeAnalysisFP.
rewrite subh1; last by rewrite [R](REC) // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(job_arrival j <= t < job_arrival j + R)
backlogged job_arrival job_cost sched j t) +
service sched j (job_arrival j + R)); last first.
@@ 761,7 +756,7 @@ Module ResponseTimeAnalysisFP.
arrives_in arr_seq j0 >
job_task j0 = tsk >
job_arrival j0 < job_arrival j >
 service sched j0 (job_arrival j0 + R) == job_cost j0).
+ service sched j0 (job_arrival j0 + R) >= job_cost j0).
{
by ins; apply IH; try (by done); rewrite ltn_add2r.
} clear IH.
diff git a/analysis/global/basic/interference_bound_edf.v b/analysis/global/basic/interference_bound_edf.v
index 513cc0b932b0fbfd5c30df7c8b09aa53be1ced35..2b6cf8a647686cd8788684b2888e788cb67ea352 100644
 a/analysis/global/basic/interference_bound_edf.v
+++ b/analysis/global/basic/interference_bound_edf.v
@@ 604,7 +604,7 @@ Module InterferenceBoundEDF.
have FST := interference_bound_edf_j_fst_is_job_of_tsk_k.
destruct FST as [FSTarr [FSTtask [LEdl _]]].
have LTr := interference_bound_edf_response_time_bound_of_j_fst_after_interval.
 apply subh3; last by apply LEdk.
+ apply subh3.
apply leq_trans with (n := job_interference job_arrival job_cost sched j_i j_fst t1
(job_arrival j_fst + R_k) + (D_k  R_k));
first by rewrite leq_add2r; apply extend_sum; [by apply leqnn].
@@ 950,8 +950,8 @@ Module InterferenceBoundEDF.
interference_caused_by j_fst t1 t2 <= D_i %% p_k  (D_k  R_k).
Proof.
intro LE.
 apply subh3; last by apply interference_bound_edf_remainder_ge_slack.
 by rewrite subndiv_eq_mod; apply subh3; last by apply leq_trunc_div.
+ apply subh3.
+ by rewrite subndiv_eq_mod; apply subh3.
Qed.
(* Next, we prove that interference caused by j_fst is bounded by the length
diff git a/analysis/global/jitter/bertogna_edf_comp.v b/analysis/global/jitter/bertogna_edf_comp.v
index 88aadea6da94c11ce90c75d121319f29523a1961..c1970889b39c9cf609b2e896b940d54e4864c7c1 100755
 a/analysis/global/jitter/bertogna_edf_comp.v
+++ b/analysis/global/jitter/bertogna_edf_comp.v
@@ 1054,8 +1054,6 @@ Module ResponseTimeIterationEDF.
have COMPLETED := RLIST tsk R HAS j ARRj JOBtsk.
exploit (DL rt_bounds tsk R);
[by ins  by ins  clear DL; intro DL].

 rewrite eqn_leq; apply/andP; split; first by apply cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + task_jitter tsk + R)); last first.
{
unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
@@ 1063,8 +1061,7 @@ Module ResponseTimeIterationEDF.
specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS2.
by rewrite JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by rewrite addnA; apply COMPLETED.
+ by rewrite addnA.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/global/jitter/bertogna_edf_theory.v b/analysis/global/jitter/bertogna_edf_theory.v
index 639feb34c01cb5574d578cde5d9798d1f3dc8899..94f3435c6ab134b5a062782b8904f60e581347a2 100644
 a/analysis/global/jitter/bertogna_edf_theory.v
+++ b/analysis/global/jitter/bertogna_edf_theory.v
@@ 228,9 +228,7 @@ Module ResponseTimeAnalysisEDFJitter.
by apply interference_bound_edf_bounds_interference with (job_deadline0 := job_deadline)
(arr_seq0 := arr_seq) (ts0 := ts); try (by done);
[ by apply bertogna_edf_tsk_other_in_ts
  by apply H_tasks_miss_no_deadlines
  by apply leq_trans with (n := task_jitter tsk + R);
 [apply leq_addl  by apply H_tasks_miss_no_deadlines]
+  by apply H_tasks_miss_no_deadlines
 by ins; apply H_all_previous_jobs_completed_on_time with (tsk_other := tsk_other)].
Qed.
@@ 252,12 +250,7 @@ Module ResponseTimeAnalysisEDFJitter.
rewrite subh1; last by rewrite [R](REC tsk) // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(t1 <= t < t1 + R)
backlogged job_arrival job_cost job_jitter sched j t) +
service sched j (t1 + R)); last first.
@@ 386,8 +379,7 @@ Module ResponseTimeAnalysisEDFJitter.
intros t j0 LEt ARR0 LE.
cut ((job_task j0) \in unzip1 rt_bounds = true); last by rewrite UNZIP FROMTS.
move => /mapP [p IN EQ]; destruct p as [tsk' R0]; simpl in *; subst tsk'.
 apply completion_monotonic with (t0 := job_arrival j0 +
 task_jitter (job_task j0) + R0); first by done.
+ apply completion_monotonic with (t0 := job_arrival j0 + task_jitter (job_task j0) + R0).
{
rewrite addnA leq_add2l.
apply leq_trans with (n := task_deadline (job_task j0));
@@ 822,7 +814,7 @@ Module ResponseTimeAnalysisEDFJitter.
job_task j0 = tsk >
(tsk, R0) \in rt_bounds >
job_arrival j0 + task_jitter tsk + R0 < job_arrival j + task_jitter tsk' + R' >
 service sched j0 (job_arrival j0 + task_jitter tsk + R0) == job_cost j0).
+ service sched j0 (job_arrival j0 + task_jitter tsk + R0) >= job_cost j0).
{
by ins; apply IH with (tsk := tsk0) (R := R0).
}
@@ 849,7 +841,7 @@ Module ResponseTimeAnalysisEDFJitter.
unfold interference_bound_edf, interference_bound_generic in LTmin.
rewrite minnAC in LTmin; apply min_lt_same in LTmin.
specialize (BASICBOUND tsk' R' j ARRj JOBtsk BEFOREok tsk_other R_other HP).
 specialize (EDFBOUND tsk' R' INbounds j ARRj JOBtsk BEFOREok tsk_other R_other HP).
+ specialize (EDFBOUND tsk' R' j ARRj JOBtsk BEFOREok tsk_other R_other HP).
unfold minn in LTmin; clear LTmin HP BASICBOUND EDFBOUND tsk; desf.
{
by apply (leq_ltn_trans BASICBOUND) in LTmin; rewrite ltnn in LTmin.
diff git a/analysis/global/jitter/bertogna_fp_comp.v b/analysis/global/jitter/bertogna_fp_comp.v
index 05dad2c7047fce1b0ed42167add5bddfe478458e..dd320475b64bfc3a8994d539b360c05a659f84b0 100644
 a/analysis/global/jitter/bertogna_fp_comp.v
+++ b/analysis/global/jitter/bertogna_fp_comp.v
@@ 306,7 +306,7 @@ Module ResponseTimeIterationFP.
rename ts into ts'; destruct ts' as [ts UNIQ]; simpl in *.
intros hp_idx idx LThp LT NEQ HP.
rewrite ltn_neqAle; apply/andP; split; first by done.
 by apply sorted_rel_implies_le_idx with (leT := higher_priority) (s := ts) (x0 := elem).
+ by apply sorted_rel_implies_le_idx with (leT := higher_priority) (xs := ts) (default := elem).
Qed.
End HighPriorityTasks.
@@ 695,8 +695,6 @@ Module ResponseTimeIterationFP.
} des.
exploit (RLIST tsk R); [by done  by apply ARRj  by done  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 cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + (task_jitter tsk + R)));
last first.
{
@@ 704,7 +702,6 @@ Module ResponseTimeIterationFP.
apply extend_sum; rewrite // leq_add2l.
by specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS2 JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
by apply COMPLETED.
Qed.
diff git a/analysis/global/jitter/bertogna_fp_theory.v b/analysis/global/jitter/bertogna_fp_theory.v
index 34c1a9f6b04cc9ef5c2eae01aab89a24eb30f6cc..df61fbd32f9a1f7eb5259d138f7cd7e63e0b8d5e 100644
 a/analysis/global/jitter/bertogna_fp_theory.v
+++ b/analysis/global/jitter/bertogna_fp_theory.v
@@ 255,12 +255,8 @@ Module ResponseTimeAnalysisFP.
rewrite subh1; last by rewrite [R](REC) // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
+
apply leq_ltn_trans with (n := (\sum_(t1 <= t < t1 + R)
backlogged job_arrival job_cost job_jitter sched j t) +
service sched j (t1 + R)); last first.
@@ 806,7 +802,7 @@ Module ResponseTimeAnalysisFP.
(* Now we start the proof. Assume by contradiction that job j
is not complete at time (job_arrival j + job_jitter j + R'). *)
rewrite addnA.
 apply completion_monotonic with (t := job_arrival j + job_jitter j + R); first by done.
+ apply completion_monotonic with (t := job_arrival j + job_jitter j + R).
{
rewrite leq_add2r leq_add2l.
specialize (PARAMS j ARRj); des.
diff git a/analysis/global/jitter/interference_bound_edf.v b/analysis/global/jitter/interference_bound_edf.v
index 88d4f551c256e8d08dfa22719a333603fa44b76f..266cd3e971732c908496159336634a480cb06a98 100644
 a/analysis/global/jitter/interference_bound_edf.v
+++ b/analysis/global/jitter/interference_bound_edf.v
@@ 660,7 +660,7 @@ Module InterferenceBoundEDFJitter.
have FST := interference_bound_edf_j_fst_is_job_of_tsk_k.
destruct FST as [FSTtask [_ [LEdl _]]].
have LTr := interference_bound_edf_response_time_bound_of_j_fst_after_interval.
 apply subh3; last by apply LEdk.
+ apply subh3.
apply leq_trans with (n := job_interference job_arrival job_cost job_jitter sched j_i
j_fst t1 (job_arrival j_fst + J_k + R_k) + (D_k  R_k  J_k)).
{
@@ 1051,8 +1051,8 @@ Module InterferenceBoundEDFJitter.
interference_caused_by j_fst t1 t2 <= D_i %% p_k  (D_k  R_k  J_k).
Proof.
intro LE.
 apply subh3; last by apply interference_bound_edf_remainder_ge_slack.
 by rewrite subndiv_eq_mod; apply subh3; last by apply leq_trunc_div.
+ apply subh3.
+ by rewrite subndiv_eq_mod; apply subh3.
Qed.
(* Next, we prove that interference caused by j_fst is bounded by the length
diff git a/analysis/global/parallel/bertogna_edf_comp.v b/analysis/global/parallel/bertogna_edf_comp.v
index 1bec09f27d7d2d229ec4f1407e3129bfd8ae6da9..8534205f8372b6064e92a0660f8992fd49a5d924 100755
 a/analysis/global/parallel/bertogna_edf_comp.v
+++ b/analysis/global/parallel/bertogna_edf_comp.v
@@ 955,8 +955,6 @@ Module ResponseTimeIterationEDF.
have COMPLETED := RLIST tsk R HAS j ARRj JOBtsk.
exploit (DL rt_bounds tsk R);
[by ins  by ins  clear DL; intro DL].

 rewrite eqn_leq; apply/andP; split; first by apply cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + R)); last first.
{
unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
@@ 964,8 +962,7 @@ Module ResponseTimeIterationEDF.
specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
by rewrite JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by apply COMPLETED.
+ by done.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/global/parallel/bertogna_edf_theory.v b/analysis/global/parallel/bertogna_edf_theory.v
index 061a619fd05f1ac89255812e9aa28854688968ec..1967f3ca77d06b0d49eb7a449012087d1134b772 100644
 a/analysis/global/parallel/bertogna_edf_theory.v
+++ b/analysis/global/parallel/bertogna_edf_theory.v
@@ 234,12 +234,7 @@ Module ResponseTimeAnalysisEDF.
rewrite subh1; last by rewrite [R](REC tsk) // leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(job_arrival j <= t < job_arrival j + R)
backlogged job_arrival job_cost sched j t) +
service sched j (job_arrival j + R)); last first.
@@ 461,7 +456,7 @@ Module ResponseTimeAnalysisEDF.
job_task j0 = tsk >
(tsk, R0) \in rt_bounds >
job_arrival j0 + R0 < job_arrival j + R' >
 service sched j0 (job_arrival j0 + R0) == job_cost j0).
+ service sched j0 (job_arrival j0 + R0) >= job_cost j0).
{
by ins; apply IH with (tsk := tsk0) (R := R0).
}
diff git a/analysis/global/parallel/bertogna_fp_comp.v b/analysis/global/parallel/bertogna_fp_comp.v
index 28cbef95c4cd06b7692d16386dcbfaa646e6d368..a13338789a7698eb63beecc36c977653617f6a8c 100644
 a/analysis/global/parallel/bertogna_fp_comp.v
+++ b/analysis/global/parallel/bertogna_fp_comp.v
@@ 304,7 +304,7 @@ Module ResponseTimeIterationFP.
rename ts into ts'; destruct ts' as [ts UNIQ]; simpl in *.
intros hp_idx idx LThp LT NEQ HP.
rewrite ltn_neqAle; apply/andP; split; first by done.
 by apply sorted_rel_implies_le_idx with (leT := higher_priority) (s := ts) (x0 := elem).
+ by apply sorted_rel_implies_le_idx with (leT := higher_priority) (xs := ts) (default := elem).
Qed.
End HighPriorityTasks.
@@ 659,7 +659,6 @@ Module ResponseTimeIterationFP.
} des.
exploit (RLIST tsk R); eauto 1; 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 cumulative_service_le_job_cost.
apply leq_trans with (n := service sched j (job_arrival j + R)); last first.
{
unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
@@ 667,8 +666,7 @@ Module ResponseTimeIterationFP.
specialize (JOBPARAMS j ARRj); des; rewrite JOBPARAMS1.
by rewrite JOBtsk.
}
 rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
 by apply COMPLETED.
+ by done.
Qed.
(* For completeness, since all jobs of the arrival sequence
diff git a/analysis/global/parallel/bertogna_fp_theory.v b/analysis/global/parallel/bertogna_fp_theory.v
index 23d9953c4102eeee076f7c82c76dc1df21b23629..f163f51e0ce0635fe950ccbbacf4ec2a0ebf3189 100644
 a/analysis/global/parallel/bertogna_fp_theory.v
+++ b/analysis/global/parallel/bertogna_fp_theory.v
@@ 228,12 +228,7 @@ Module ResponseTimeAnalysisFP.
rewrite subh1; last by rewrite REC leq_addr.
rewrite addnBA // subnn addn0.
move: (NOTCOMP) => /negP NOTCOMP'.
 rewrite neq_ltn in NOTCOMP.
 move: NOTCOMP => /orP [LT  BUG]; last first.
 {
 exfalso; rewrite ltnNge in BUG; move: BUG => /negP BUG; apply BUG.
 by apply cumulative_service_le_job_cost.
 }
+ rewrite ltnNge in NOTCOMP.
apply leq_ltn_trans with (n := (\sum_(job_arrival j <= t < job_arrival j + R)
backlogged job_arrival job_cost sched j t) +
service sched j (job_arrival j + R)); last first.
@@ 448,7 +443,7 @@ Module ResponseTimeAnalysisFP.
arrives_in arr_seq j0 >
job_task j0 = tsk >
job_arrival j0 < job_arrival j >
 service sched j0 (job_arrival j0 + R) == job_cost j0).
+ service sched j0 (job_arrival j0 + R) >= job_cost j0).
{
by ins; apply IH; try (by done); rewrite ltn_add2r.
} clear IH.
diff git a/analysis/uni/arrival_curves/workload_bound.v b/analysis/uni/arrival_curves/workload_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..e0ac7c1bee24033c74acc623edd48f25fa4b4c86
 /dev/null
+++ b/analysis/uni/arrival_curves/workload_bound.v
@@ 0,0 +1,349 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule.
+Require Import rt.model.arrival.curves.bounds.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+Module MaxArrivalsWorkloadBound.
+
+ Import Job ArrivalCurves TaskArrival Priority UniprocessorSchedule Workload Service.
+
+ Section Lemmas.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence. *)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* Consider an FP policy that indicates a higherorequal priority relation. *)
+ Variable higher_eq_priority: FP_policy Task.
+ Let jlfp_higher_eq_priority := FP_to_JLFP job_task higher_eq_priority.
+
+ (* For simplicity, let's define some local names. *)
+ Let arrivals_between := jobs_arrived_between arr_seq.
+
+ (* We define the notion of request bound function. *)
+ Section RequestBoundFunction.
+
+ (* Let max_arrivals denote any function that takes a task and an interval length
+ and returns the associated number of job arrivals of the task. *)
+ Variable max_arrivals: Task > time > nat.
+
+ (* In this section, we define a bound for the workload of a single task
+ under uniprocessor FP scheduling. *)
+ Section SingleTask.
+
+ (* Consider any task tsk that is to be scheduled in an interval of length delta. *)
+ Variable tsk: Task.
+ Variable delta: time.
+
+ (* We define the following workload bound for the task. *)
+ Definition task_request_bound_function := task_cost tsk * max_arrivals tsk delta.
+
+ End SingleTask.
+
+ (* In this section, we define a bound for the workload of multiple tasks. *)
+ Section AllTasks.
+
+ (* Consider a task set ts... *)
+ Variable ts: list Task.
+
+ (* ...and let tsk be any task in task set. *)
+ Variable tsk: Task.
+
+ (* Let delta be the length of the interval of interest. *)
+ Variable delta: time.
+
+ (* Recall the definition of higherorequalpriority task and
+ the pertask workload bound for FP scheduling. *)
+ Let is_hep_task tsk_other := higher_eq_priority tsk_other tsk.
+ Let is_other_hep_task tsk_other := higher_eq_priority tsk_other tsk && (tsk_other != tsk).
+
+ (* Using the sum of individual workload bounds, we define the following bound
+ for the total workload of tasks in any interval of length delta. *)
+ Definition total_request_bound_function :=
+ \sum_(tsk < ts) task_request_bound_function tsk delta.
+
+ (* Similarly, we define the following bound for the total workload of tasks of
+ higherorequal priority (with respect to tsk) in any interval of length delta. *)
+ Definition total_hep_request_bound_function_FP :=
+ \sum_(tsk_other < ts  is_hep_task tsk_other)
+ task_request_bound_function tsk_other delta.
+
+ (* We also define bound for the total workload of higherorequal priority
+ tasks other than tsk in any interval of length delta. *)
+ Definition total_ohep_request_bound_function_FP :=
+ \sum_(tsk_other < ts  is_other_hep_task tsk_other)
+ task_request_bound_function tsk_other delta.
+
+ End AllTasks.
+
+ End RequestBoundFunction.
+
+ (* In this section we prove some lemmas about request bound functions. *)
+ Section ProofWorkloadBound.
+
+ (* Consider a task set ts... *)
+ Variable ts: list Task.
+
+ (* ...and let tsk be any task in ts. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Assume that a job cost cannot be larger than a task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ forall j,
+ arrives_in arr_seq j >
+ job_cost_le_task_cost task_cost job_cost job_task j.
+
+ (* Next, we assume that all jobs come from the task set. *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* Let max_arrivals be any arrival bound for taskset ts. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_is_arrival_bound:
+ is_arrival_bound_for_taskset job_task arr_seq max_arrivals ts.
+
+ (* Let's define some local names for clarity. *)
+ Let task_rbf := task_request_bound_function max_arrivals tsk.
+ Let total_rbf := total_request_bound_function max_arrivals ts.
+ Let total_hep_rbf := total_hep_request_bound_function_FP max_arrivals ts tsk.
+ Let total_ohep_rbf := total_ohep_request_bound_function_FP max_arrivals ts tsk.
+
+ (* Next, we consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+
+ (* We define whether two jobs j1 and j2 are from the same task. *)
+ Let same_task j1 j2 := job_task j1 == job_task j2.
+
+ (* Next, we say that two jobs j1 and j2 are in relation other_higher_eq_priority, iff
+ j1 has higher or equal priority than j2 and is produced by a different task. *)
+ Let other_higher_eq_priority j1 j2 := jlfp_higher_eq_priority j1 j2 && (~~ same_task j1 j2).
+
+ (* Next, we recall the notions of total workload of jobs... *)
+ Let total_workload t1 t2 :=
+ workload_of_jobs job_cost (arrivals_between t1 t2) (fun j => true).
+
+ (* ...notions of workload of higher or equal priority jobs... *)
+ Let total_hep_workload t1 t2 :=
+ workload_of_jobs job_cost (arrivals_between t1 t2)
+ (fun j_other => jlfp_higher_eq_priority j_other j).
+
+ (* ... workload of other higher or equal priority jobs... *)
+ Let total_ohep_workload t1 t2 :=
+ workload_of_jobs job_cost (arrivals_between t1 t2)
+ (fun j_other => other_higher_eq_priority j_other j).
+
+ (* ... and the workload of jobs of the same task as job j. *)
+ Let task_workload (t1: time) (t2: time) :=
+ workload_of_jobs job_cost (arrivals_between t1 t2)
+ (fun j_other => same_task j_other j).
+
+ (* In this section we prove that the workload of any jobs is
+ no larger than the request bound function. *)
+ Section WorkloadIsBoundedByRBF.
+
+ (* Consider any time t and any interval of length delta. *)
+ Variable t: time.
+ Variable delta: time.
+
+ (* First, we prove that workload of task is no larger
+ than task request bound function. *)
+ Lemma task_workload_le_task_rbf:
+ task_workload t (t + delta) <= task_rbf delta.
+ Proof.
+ unfold task_workload.
+ unfold task_rbf, task_request_bound_function.
+ unfold is_arrival_bound in *.
+ unfold arrivals_between.
+
+ set l := jobs_arrived_between arr_seq t delta.
+ apply leq_trans with (
+ task_cost tsk * num_arrivals_of_task job_task arr_seq tsk t (t + delta)).
+ {
+ rewrite /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /l /workload_of_jobs.
+ rewrite /is_job_of_task /same_task H_job_of_tsk muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ rewrite EQ.
+ apply H_job_cost_le_task_cost.
+ by apply in_arrivals_implies_arrived in IN0.
+ }
+ {
+ rewrite leq_mul2l; apply/orP; right.
+ rewrite {2}[delta](addKn t).
+ apply H_is_arrival_bound; first by done.
+ by rewrite leq_addr.
+ }
+ Qed.
+
+ (* Next, we prove that total workload of tasks is no larger
+ than total request bound function. *)
+ Lemma total_workload_le_total_rbf:
+ total_ohep_workload t (t + delta) <= total_ohep_rbf delta.
+ Proof.
+ rewrite /total_ohep_rbf /total_ohep_request_bound_function_FP
+ /task_request_bound_function.
+ rewrite /total_ohep_workload /workload_of_jobs
+ /other_higher_eq_priority.
+ rewrite /jlfp_higher_eq_priority
+ /FP_to_JLFP /same_task H_job_of_tsk.
+ rewrite /arrivals_between.
+
+ set l := jobs_arrived_between arr_seq t (t + delta).
+ set hep := higher_eq_priority.
+
+ apply leq_trans with
+ (\sum_(tsk' < ts  hep tsk' tsk && (tsk' != tsk))
+ (\sum_(j0 < l  job_task j0 == tsk') job_cost j0)).
+ {
+ intros.
+ have EXCHANGE :=
+ exchange_big_dep
+ (fun x => hep (job_task x) tsk && (job_task x != tsk)).
+ rewrite EXCHANGE /=; last by move => tsk0 j0 HEP /eqP JOB0; rewrite JOB0.
+ rewrite /workload_of_jobs /l big_seq_cond [X in _ <= X]big_seq_cond.
+ apply leq_sum; move => j0 /andP [IN0 HP0].
+ rewrite big_mkcond (big_rem (job_task j0)) /=;
+ first by rewrite HP0 andTb eq_refl; apply leq_addr.
+ by apply in_arrivals_implies_arrived in IN0;
+ apply H_all_jobs_from_taskset.
+ }
+ apply leq_sum_seq; intros tsk0 INtsk0 HP0.
+ apply leq_trans with (
+ task_cost tsk0 * num_arrivals_of_task job_task arr_seq tsk0 t (t + delta)).
+ {
+ rewrite /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /l /workload_of_jobs.
+ rewrite /is_job_of_task muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ rewrite EQ.
+ apply H_job_cost_le_task_cost.
+ by apply in_arrivals_implies_arrived in IN0.
+ }
+ {
+ rewrite leq_mul2l; apply/orP; right.
+ rewrite {2}[delta](addKn t).
+ apply H_is_arrival_bound; first by done.
+ by rewrite leq_addr.
+ }
+ Qed.
+
+ Lemma total_workload_le_total_rbf':
+ total_hep_workload t (t + delta) <= total_hep_rbf delta.
+ Proof.
+ intros.
+ rewrite /total_hep_rbf /total_hep_request_bound_function_FP
+ /task_request_bound_function.
+ rewrite /total_hep_workload /workload_of_jobs
+ /jlfp_higher_eq_priority /FP_to_JLFP /same_task H_job_of_tsk.
+ rewrite /arrivals_between.
+
+ set l := jobs_arrived_between arr_seq t (t + delta).
+ set hep := higher_eq_priority.
+
+ apply leq_trans with
+ (n := \sum_(tsk' < ts  hep tsk' tsk)
+ (\sum_(j0 < l  job_task j0 == tsk') job_cost j0)).
+ {
+ intros.
+ have EXCHANGE := exchange_big_dep (fun x => hep (job_task x) tsk).
+ rewrite EXCHANGE /=; last by move => tsk0 j0 HEP /eqP JOB0; rewrite JOB0.
+ rewrite /workload_of_jobs /l big_seq_cond [X in _ <= X]big_seq_cond.
+ apply leq_sum; move => j0 /andP [IN0 HP0].
+ rewrite big_mkcond (big_rem (job_task j0)) /=;
+ first by rewrite HP0 andTb eq_refl; apply leq_addr.
+ by apply in_arrivals_implies_arrived in IN0;
+ apply H_all_jobs_from_taskset.
+ }
+ apply leq_sum_seq; intros tsk0 INtsk0 HP0.
+ apply leq_trans with (
+ task_cost tsk0 * num_arrivals_of_task job_task arr_seq tsk0 t (t + delta)).
+ {
+ rewrite /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /l /workload_of_jobs.
+ rewrite /is_job_of_task muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ rewrite EQ.
+ apply H_job_cost_le_task_cost.
+ by apply in_arrivals_implies_arrived in IN0.
+ }
+ {
+ rewrite leq_mul2l; apply/orP; right.
+ rewrite {2}[delta](addKn t).
+ apply H_is_arrival_bound; [by done  by rewrite leq_addr].
+ }
+ Qed.
+
+ Lemma total_workload_le_total_rbf'':
+ total_workload t (t + delta) <= total_rbf delta.
+ Proof.
+ intros.
+ rewrite /total_rbf
+ /task_request_bound_function.
+ rewrite /total_workload /workload_of_jobs.
+ rewrite /arrivals_between.
+
+ set l := jobs_arrived_between arr_seq t (t + delta).
+ rewrite big_mkcond //=.
+
+
+ apply leq_trans with
+ (n := \sum_(tsk' < ts)
+ (\sum_(j0 < l  job_task j0 == tsk') job_cost j0)).
+ {
+ intros.
+ have EXCHANGE := exchange_big_dep predT.
+ rewrite EXCHANGE /=; last by done.
+ rewrite /workload_of_jobs /l big_seq_cond [X in _ <= X]big_seq_cond.
+ apply leq_sum; move => j0 /andP [IN0 HP0].
+ rewrite big_mkcond (big_rem (job_task j0)) /=.
+ rewrite eq_refl; apply leq_addr.
+ by apply in_arrivals_implies_arrived in IN0;
+ apply H_all_jobs_from_taskset.
+ }
+ apply leq_sum_seq; intros tsk0 INtsk0 HP0.
+ apply leq_trans with (
+ task_cost tsk0 * num_arrivals_of_task job_task arr_seq tsk0 t (t + delta)).
+ {
+ rewrite /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /l /workload_of_jobs.
+ rewrite /is_job_of_task muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ rewrite EQ.
+ apply H_job_cost_le_task_cost.
+ by apply in_arrivals_implies_arrived in IN0.
+ }
+ {
+ rewrite leq_mul2l; apply/orP; right.
+ rewrite {2}[delta](addKn t).
+ apply H_is_arrival_bound; [by done  by rewrite leq_addr].
+ }
+ Qed.
+
+ End WorkloadIsBoundedByRBF.
+
+ End ProofWorkloadBound.
+
+ End Lemmas.
+
+End MaxArrivalsWorkloadBound.
\ No newline at end of file
diff git a/analysis/uni/basic/fp_rta_theory.v b/analysis/uni/basic/fp_rta_theory.v
index 9b5fae2e344fea460df3f7ee95fde6f7073e840a..262c13ff0224a045d6720320e199fa7951bbe8fd 100644
 a/analysis/uni/basic/fp_rta_theory.v
+++ b/analysis/uni/basic/fp_rta_theory.v
@@ 4,7 +4,7 @@ Require Import rt.model.arrival.basic.job rt.model.arrival.basic.task rt.model.p
Require Import rt.model.schedule.uni.schedule_of_task rt.model.schedule.uni.workload
rt.model.schedule.uni.schedulability rt.model.schedule.uni.response_time
rt.model.schedule.uni.service.
Require Import rt.model.schedule.uni.basic.busy_interval rt.model.schedule.uni.basic.platform.
+Require Import rt.model.schedule.uni.limited.busy_interval rt.model.schedule.uni.basic.platform.
Require Import rt.analysis.uni.basic.workload_bound_fp.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
@@ 12,7 +12,7 @@ Module ResponseTimeAnalysisFP.
Import Job ScheduleOfTask SporadicTaskset Priority ResponseTime
TaskArrival ArrivalBounds WorkloadBoundFP Platform Schedulability
 BusyInterval Workload Service.
+ BusyIntervalJLFP Workload Service.
(* In this section, we prove that any fixed point in the RTA for uniprocessor
FP scheduling is a responsetime bound. *)
@@ 98,15 +98,42 @@ Module ResponseTimeAnalysisFP.
Proof.
rename H_response_time_is_fixed_point into FIX.
intros j ARRj JOBtsk.
+ move: (posnP (job_cost j)) => [ZPOS].
+ { by rewrite /is_response_time_bound_of_job /completed_by Z. }
set prio := FP_to_JLFP job_task higher_eq_priority.
 apply busy_interval_bounds_response_time with (arr_seq0 := arr_seq)
 (higher_eq_priority0 := prio); try (by done).
  by intros x; apply H_priority_is_reflexive.
  by intros x z y; apply H_priority_is_transitive.
 apply fp_workload_bound_holds with (job_arrival0 := job_arrival) (task_cost0 := task_cost)
 (task_period0 := task_period) (task_deadline0 := task_deadline)
 (job_deadline0 := job_deadline) (ts0 := ts); try (by done).
 by rewrite JOBtsk.
+ apply busy_interval_bounds_response_time with
+ (arr_seq0 := arr_seq)
+ (higher_eq_priority0 := prio)
+ (priority_inversion_bound := 0); try by done.
+  by intros x; apply H_priority_is_reflexive.
+ { intros t1 t2 BUSY.
+ rewrite /cumulative_priority_inversion /is_priority_inversion leqn0.
+ rewrite big_nat big1 //; move => t NEQ.
+ destruct (sched t) eqn:SCHED; last by done.
+ have HP := pending_hp_job_exists
+ job_arrival job_cost arr_seq _ sched
+ prio _ ARRj _ _ _ _ _ BUSY _ NEQ.
+ feed_n 4 HP; try done.
+ { by intros x; apply H_priority_is_reflexive. }
+ move: HP => [jhp [ARRjhp [PEND PRIO]]].
+ apply/eqP; rewrite eqb0 Bool.negb_involutive.
+ rewrite /prio /FP_to_JLFP.
+ eapply H_priority_is_transitive with (job_task jhp); last by done.
+ destruct (s == jhp) eqn:EQ; first by move: EQ => /eqP EQ; subst s.
+ apply H_respects_fp_policy with t; try done.
+ { apply/andP; split; first by done.
+ rewrite /scheduled_at SCHED.
+ apply/negP. intros SNEQ; move: SNEQ => /eqP SNEQ.
+ move: EQ => /negP EQ; apply EQ.
+ by inversion SNEQ.
+ }
+ { by rewrite /scheduled_at SCHED. }
+ }
+ apply fp_workload_bound_holds with
+ (job_arrival0 := job_arrival) (task_cost0 := task_cost)
+ (task_period0 := task_period) (task_deadline0 := task_deadline)
+ (job_deadline0 := job_deadline) (ts0 := ts); try (by done).
+ by rewrite JOBtsk.
Qed.
End ResponseTimeBound.
diff git a/analysis/uni/basic/tdma_rta_theory.v b/analysis/uni/basic/tdma_rta_theory.v
index dfe84fce0f4f94d43c285dc5fbf17e9e07d86520..c71832679ef8d51d801839839870b63db430fe2e 100644
 a/analysis/uni/basic/tdma_rta_theory.v
+++ b/analysis/uni/basic/tdma_rta_theory.v
@@ 187,7 +187,7 @@ Module ResponseTimeAnalysisTDMA.
Theorem uniprocessor_response_time_bound_TDMA: response_time_bounded_by tsk BOUND.
Proof.
intros j arr_seq_j JobTsk.
 apply completion_monotonic with (t:=job_arrival j + RT j);first exact.
+ apply completion_monotonic with (t:=job_arrival j + RT j); try done.
 rewrite leq_add2l /BOUND.
apply (response_time_le_WCRT)
with (task_cost0:=task_cost) (task_deadline0:=task_deadline)(sched0:=sched)
diff git a/analysis/uni/basic/tdma_wcrt_analysis.v b/analysis/uni/basic/tdma_wcrt_analysis.v
index 7c81dc2ede456d24a8bcbae649957c06648a4021..54845225ac78b170cf7996f81626a82656484794 100644
 a/analysis/uni/basic/tdma_wcrt_analysis.v
+++ b/analysis/uni/basic/tdma_wcrt_analysis.v
@@ 186,8 +186,8 @@ Import Job TaskArrival ScheduleOfTask ResponseTime Platform_TDMA end_time Sche
 rewrite /has_arrived. auto.
 rewrite /completed_by /service /service_during.
rewrite >cumulative_service_before_job_arrival_zero
 with (job_arrival0:=job_arrival). rewrite neq_ltn. apply /orP.
 left. apply H_valid_job. apply H_jobs_must_arrive_to_execute. auto.
+ with (job_arrival0:=job_arrival). rewrite ltnNge.
+ apply H_valid_job. apply H_jobs_must_arrive_to_execute. auto.
Qed.
(* Job is pending at t.+1 if
@@ 386,7 +386,7 @@ Import Job TaskArrival ScheduleOfTask ResponseTime Platform_TDMA end_time Sche
rewrite case2 Hcases. repeat rewrite addSn case1 subn1 subKn //.
repeat rewrite subn0.
case Hc_slot:(c < time_slot); rewrite /duration_to_finish_from_start_of_slot_with.
 * by rewrite ceil_eq1.
+ * by rewrite ceil_eq1 //; ssromega.
* rewrite ceil_suba //; try ssromega.
rewrite subn1 mulnBl mul1n addnA addSn addn1.
apply/eqP. rewrite eqn_add2l subnBA // addnA. repeat rewrite addnBA; try ssromega.
@@ 834,4 +834,4 @@ Import Job TaskArrival ScheduleOfTask ResponseTime Platform_TDMA end_time Sche
End WCRT_analysis.
End WCRT_OneJobTDMA.
\ No newline at end of file
+End WCRT_OneJobTDMA.
diff git a/analysis/uni/susp/dynamic/jitter/jitter_schedule_properties.v b/analysis/uni/susp/dynamic/jitter/jitter_schedule_properties.v
index 67e68044bed7aca99b017b24d67ffe73cb519592..b0be1d89a8a74f8e4b61f8586737945246d3a299 100644
 a/analysis/uni/susp/dynamic/jitter/jitter_schedule_properties.v
+++ b/analysis/uni/susp/dynamic/jitter/jitter_schedule_properties.v
@@ 244,10 +244,9 @@ Module JitterScheduleProperties.
rewrite sched_jitter_uses_construction_function /reduction.build_schedule
/hp_job_other_than_j.
destruct (hp_job_other_than_j t) as [j_hp] eqn:HP; last first.
 {
 case PENDj: pending; last by done.
+ { case PENDj: pending; last by done.
apply/eqP; case => SAME; subst j0; move: PENDj => /andP [_ NOTCOMPj].
 by rewrite /completed_by EQ eq_refl in NOTCOMPj.
+ by rewrite /completed_by EQ leqnn in NOTCOMPj.
}
rewrite /hp_job_other_than_j /reduction.highest_priority_job_other_than_j in HP.
apply seq_min_in_seq in HP; rewrite mem_filter /pending /completed_by in HP.
@@ 256,12 +255,12 @@ Module JitterScheduleProperties.
{
move: PENDj => /andP [_ NOTCOMPj].
case: (~~ higher_eq_priority _ _); apply/eqP; case => SAME; subst j0;
 first by rewrite /completed_by EQ eq_refl in NOTCOMPj.
 by rewrite EQ eq_refl in NOTCOMPhp.
+ first by rewrite /completed_by EQ leqnn in NOTCOMPj.
+ by rewrite EQ leqnn in NOTCOMPhp.
}
{
apply/eqP; case => SAME; subst j0.
 by rewrite EQ eq_refl in NOTCOMPhp.
+ by rewrite EQ leqnn in NOTCOMPhp.
}
Qed.
diff git a/analysis/uni/susp/dynamic/jitter/jitter_schedule_service.v b/analysis/uni/susp/dynamic/jitter/jitter_schedule_service.v
index c5d88d837adab7690a75959ae818fa71e74c53de..6bf7db9a9e8a84ac2080cf5a38234f8e0e7bb2e3 100644
 a/analysis/uni/susp/dynamic/jitter/jitter_schedule_service.v
+++ b/analysis/uni/susp/dynamic/jitter/jitter_schedule_service.v
@@ 257,11 +257,9 @@ Module JitterScheduleService.
by apply actual_arrivals_between_sub with (t3 := 0) (t4 := t).
}
apply leq_sum_seq; rewrite /act /actual_arrivals; intros j0 IN0 HP0.
 apply eq_leq; symmetry; apply/eqP.
 have ARRin: arrives_in arr_seq j0.
 by apply in_actual_arrivals_between_implies_arrived in IN0.
 apply in_actual_arrivals_implies_arrived_before in IN0.
 by apply WORK.
+ apply WORK; try done.
+  by apply in_actual_arrivals_between_implies_arrived in IN0.
+  by apply in_actual_arrivals_implies_arrived_before in IN0.
Qed.
End ServiceEqualsWorkload.
@@ 378,9 +376,7 @@ Module JitterScheduleService.
}
rewrite /inflated_job_cost /reduction.inflated_job_cost.
apply negbTE in NEQ; rewrite NEQ.
 apply eq_leq; symmetry; apply/eqP.
 apply completion_monotonic with (t := arr_hp + job_deadline j_hp);
 [by done   by apply NOMISS].
+ apply completion_monotonic with (t := arr_hp + job_deadline j_hp); last by apply NOMISS.
rewrite H_job_deadlines_equal_task_deadlines //.
apply leq_trans with (n := arr_hp + task_period (job_task j_hp));
first by rewrite leq_add2l DL // FROM.
@@ 458,7 +454,7 @@ Module JitterScheduleService.
apply leq_trans with (n := service sched_susp j_hp (arr_hp + Rhp));
last by apply extend_sum.
apply leq_trans with (n := cost_hp);
 last by apply eq_leq; symmetry; apply/eqP; apply RESPhp; last by apply/andP; split.
+ last by apply RESPhp; last by apply/andP; split.
apply leq_trans with (n := inflated_job_cost j_hp);
last by rewrite /inflated_job_cost /reduction.inflated_job_cost [_==_]negbK NEQ.
apply cumulative_service_le_job_cost.
@@ 507,7 +503,7 @@ Module JitterScheduleService.
{
rewrite /cost_hp leq_subLR.
apply leq_trans with (n := service sched_susp j_hp (arr_hp + Rhp));
 first by apply eq_leq;symmetry;apply/eqP; apply RESPhp; last by apply/andP; split.
+ first by apply RESPhp; last by apply/andP; split.
rewrite /service /service_during.
apply leq_trans with (n := \sum_(arr_j <= t' < arr_hp+Rhp)
1 + service sched_susp j_hp arr_j);
@@ 527,7 +523,7 @@ Module JitterScheduleService.
have LEcost: cost_hp <= Rhp.
{
apply leq_trans with (n := service sched_susp j_hp (arr_hp + Rhp));
 first by apply eq_leq;symmetry;apply/eqP;apply RESPhp; last by apply/andP;split.
+ first by apply RESPhp; last by apply/andP;split.
apply leq_trans with (n := \sum_(arr_hp <= t' < arr_hp + Rhp) 1);
last by simpl_sum_const; rewrite addKn.
rewrite /service /service_during.
@@ 755,16 +751,7 @@ Module JitterScheduleService.
set TSj := fun a b => \sum_(a <= t0 < b)
\sum_(j_hp < act 0 t2  hep j_hp) SCHj j_hp t0.
rewrite /(TSs t1 (t1 + d).+1) /(TSs 0 t1).
 rewrite subh3 //; last first.
 {
 apply leq_trans with (n := TSs 0 (t1 + d).+1).
 {
 apply extend_sum; try (by done).
 by apply leq_trans with (n := t1 + d); first by apply leq_addr.
 }
 rewrite /TSs exchange_big /=.
 by apply LEWORKs.
 }
+ rewrite subh3 //.
rewrite addnC big_cat_nat //=;
last by apply leq_trans with (n := t1 + d); first by apply leq_addr.
by rewrite exchange_big; apply LEWORKs; rewrite ltn_add2l.
@@ 880,8 +867,7 @@ Module JitterScheduleService.
feed (EQWORKj (t1 + d).+1); first by rewrite ltn_add2l.
apply EQWORKj.
intros j0 ARRin0 ARR0 HEP0; specialize (ALL j0 ARRin0 HEP0 ARR0).
 by apply completion_monotonic with (t := t1 + d);
 first by apply reduction_prop.sched_jitter_completed_jobs_dont_execute.
+ by apply completion_monotonic with (t := t1 + d).
Qed.
(* By combining each inequality above in sequence, we complete the induction
@@ 1116,12 +1102,7 @@ Module JitterScheduleService.
feed AFTERj; try done.
set Sj := service_during sched_jitter j arr_j.
set Shp := service_of_other_hep_jobs_in_sched_jitter arr_j.
 rewrite subh3 //; last first.
 {
 rewrite /Shp /service_of_other_hep_jobs_in_sched_jitter.
 rewrite [X in _ <= X](addKn arr_j).
 by apply service_of_jobs_le_delta, actual_arrivals_uniq.
 }
+ rewrite subh3 //.
apply leq_trans with (n := \sum_(arr_j <= t < arr_j + R_j) 1);
last by simpl_sum_const; rewrite addKn.
rewrite /Sj /Shp /service_of_other_hep_jobs_in_sched_jitter /service_of_jobs
@@ 1245,33 +1226,30 @@ Module JitterScheduleService.
is also bounded by R_j. *)
Corollary jitter_reduction_job_j_completes_no_later:
job_response_time_in_sched_susp_bounded_by j R_j.
 Proof.
+ Proof.
move: (H_valid_schedule) => [_ [MUSTARRs [COMPs [WORK [PRIO SELF]]]]].
rename H_response_time_of_j_in_sched_jitter into COMPj.
apply contraT; intro NOTCOMPs.
suff NOTCOMPj: ~~ job_response_time_in_sched_jitter_bounded_by j R_j;
[by rewrite COMPj in NOTCOMPj  clear COMPj].
have LESS := jitter_reduction_less_service_for_job_j NOTCOMPs.
 rewrite neq_ltn; apply/orP; left.
+ rewrite ltnNge.
rewrite /inflated_job_cost /reduction.inflated_job_cost eq_refl.
apply leq_ltn_trans with (n := service_during sched_jitter j arr_j (arr_j + R_j)).
 {
 rewrite /service /service_during.
+ { rewrite /service /service_during.
rewrite (ignore_service_before_arrival job_arrival) ?leq_addr //.
apply jobs_with_jitter_must_arrive_to_execute with (job_jitter0 := job_jitter).
 by apply reduction_prop.sched_jitter_jobs_execute_after_jitter.
+ by apply reduction_prop.sched_jitter_jobs_execute_after_jitter.
}
apply: (leq_ltn_trans LESS).
rewrite addn1 addnA [_ + 1]addnC addnA; apply leq_add.
 {
 rewrite addn1; apply contraT; rewrite leqNgt; intro LE.
+ { rewrite addn1; apply contraT; rewrite leqNgt; intro LE.
exfalso; move: NOTCOMPs => /negP NOTCOMPs; apply: NOTCOMPs.
rewrite /job_response_time_in_sched_susp_bounded_by /is_response_time_bound_of_job.
 rewrite /completed_by eqn_leq; apply/andP; split;
 first by apply cumulative_service_le_job_cost.
+ rewrite /completed_by.
apply: (leq_trans LE).
rewrite /service /service_during.
 by rewrite [X in _ <= X](ignore_service_before_arrival job_arrival) ?leq_addr.
+ by rewrite [X in _ <= X](ignore_service_before_arrival job_arrival) ?leq_addr.
}
by apply cumulative_suspension_le_total_suspension.
Qed.
diff git a/analysis/uni/susp/dynamic/jitter/rta_by_reduction.v b/analysis/uni/susp/dynamic/jitter/rta_by_reduction.v
index 21ebe100fbd9c29fdbb25ebe0a58c52e0b5fc94c..aadfaeda9ee6ae7c029669a7a7e5b190e18f8f20 100644
 a/analysis/uni/susp/dynamic/jitter/rta_by_reduction.v
+++ b/analysis/uni/susp/dynamic/jitter/rta_by_reduction.v
@@ 188,8 +188,8 @@ Module RTAByReduction.
{
intros j_hp ARRhp OTHERhp.
rewrite /actual_response_time.
 apply pick_min_holds; last by intros r RESP _.
 exists (Ordinal (ltnSn (R (job_task j_hp)))).
+ apply pick_min_holds; last by intros r _ RESP _.
+ exists (R (job_task j_hp)); split; first by done.
by apply RESPhp; try (by done); [by apply FROM  rewrite /other_hep_task H_job_of_tsk].
}
{
diff git a/analysis/uni/susp/dynamic/jitter/taskset_membership.v b/analysis/uni/susp/dynamic/jitter/taskset_membership.v
index 40a2fb460d92665524c81dd5147bab3600381121..f16e79e95927c739d252ebdf4c605b03cab0fa5d 100644
 a/analysis/uni/susp/dynamic/jitter/taskset_membership.v
+++ b/analysis/uni/susp/dynamic/jitter/taskset_membership.v
@@ 133,7 +133,7 @@ Module TaskSetMembership.
intros j_hp ARRhp HP.
rewrite /actual_response_time.
apply pick_min_holds; last by done.
 exists (Ordinal (ltnSn (R (job_task j_hp)))). simpl.
+ exists (R (job_task j_hp)); split; first by done.
by apply RESPhp; try (by done); first by apply FROM.
Qed.
@@ 153,14 +153,14 @@ Module TaskSetMembership.
rewrite /actual_response_time.
apply pick_min_holds;
last by intros x RESPx _ MINx; rewrite ltnS in LT; apply (MINx (Ordinal LT)).
 exists (Ordinal (ltnSn (R (job_task j_hp)))).
+ exists (R (job_task j_hp)); split; first by done.
by apply RESPhp; try (by done); first by apply FROM.
}
{
apply leq_trans with (n := (R (job_task j_hp))); last by apply ltnW.
rewrite ltnS /actual_response_time.
apply pick_min_ltn.
 exists (Ordinal (ltnSn (R (job_task j_hp)))). simpl.
+ exists (R (job_task j_hp)); split; first by done.
by apply RESPhp; try (by done); first by apply FROM.
}
Qed.
diff git a/analysis/uni/susp/dynamic/jitter/taskset_rta.v b/analysis/uni/susp/dynamic/jitter/taskset_rta.v
index 400d139f54079fcabfc04b9047a0563ea3147de6..b16172b1110df6e0825e7928ffa5a78b287fbd71 100644
 a/analysis/uni/susp/dynamic/jitter/taskset_rta.v
+++ b/analysis/uni/susp/dynamic/jitter/taskset_rta.v
@@ 214,7 +214,7 @@ Module TaskSetRTA.
{
intros j0 ARR0 LT0 JOB0.
apply completion_monotonic with (t := job_arrival j0 + R tsk_i);
 [by done   by apply BEFOREok; rewrite // JOBtsk].
+ [  by apply BEFOREok; rewrite // JOBtsk].
by rewrite leq_add2l H_job_deadline_eq_task_deadline // JOB0 JOBtsk.
}
{
diff git a/analysis/uni/susp/dynamic/oblivious/reduction.v b/analysis/uni/susp/dynamic/oblivious/reduction.v
index fef1c014cbad4dd1a394d5f950edc7122b443f05..e956170578754ee78edbc49a069f3de6ea1dadf2 100644
 a/analysis/uni/susp/dynamic/oblivious/reduction.v
+++ b/analysis/uni/susp/dynamic/oblivious/reduction.v
@@ 320,14 +320,14 @@ Module ReductionToBasicSchedule.
{
apply/eqP; case => SAME; subst.
move: PEND => /andP [PEND _].
 by rewrite /pending /completed_by EQ eq_refl andbF in PEND.
+ by rewrite /pending /completed_by EQ leqnn andbF in PEND.
}
{
apply/eqP; case => SAME; subst.
suff IN: j \in pending_jobs sched_new t.
{
rewrite mem_filter in IN; move: IN => /andP [/andP [_ NOTCOMP] _].
 by rewrite /completed_by EQ eq_refl in NOTCOMP.
+ by rewrite /completed_by EQ leqnn in NOTCOMP.
}
by apply: (seq_min_in_seq (higher_eq_priority t)).
}
@@ 337,7 +337,7 @@ Module ReductionToBasicSchedule.
suff IN: j \in pending_jobs sched_new t.
{
rewrite mem_filter in IN; move: IN => /andP [/andP [_ NOTCOMP] _].
 by rewrite /completed_by EQ eq_refl in NOTCOMP.
+ by rewrite /completed_by EQ leqnn in NOTCOMP.
}
by apply: (seq_min_in_seq (higher_eq_priority t)).
}
@@ 490,20 +490,15 @@ Module ReductionToBasicSchedule.
rename H_j_has_completed into COMP, H_induction_hypothesis into IH.
apply leq_trans with (n := original_job_cost j +
total_suspension original_job_cost next_suspension j).
 {
 by apply leq_trans with (n := inflated_job_cost j);
 first by apply cumulative_service_le_job_cost,
 sched_new_completed_jobs_dont_execute.
+ { by apply leq_trans with (n := inflated_job_cost j);
+ first apply cumulative_service_le_job_cost,
+ sched_new_completed_jobs_dont_execute.
}
 have SERVs: job_service_with_suspensions j t.+1 = original_job_cost j.
 {
 by apply/eqP; apply completion_monotonic with (t0 := t).
 } rewrite SERVs; clear SERVs.
 rewrite leq_add2l.
 apply completion_monotonic with (t' := t.+1) in COMP; try (by done).
+ rewrite leq_add //; first by apply completion_monotonic with (t0 := t).
+ apply completion_monotonic with (t' := t.+1) in COMP; try done.
rewrite /job_cumulative_suspension.
by rewrite > cumulative_suspension_eq_total_suspension with
 (job_cost := original_job_cost).
+ (job_cost := original_job_cost).
Qed.
End CompletedInSuspensionAwareSchedule.
@@ 520,6 +515,8 @@ Module ReductionToBasicSchedule.
preserved in the interval [0, t), now we only have to consider the state of job j
at time t in both schedules. That is, we need to prove the following property:
+
+
scheduled_at sched_new j t <=
job_suspended_at sched_susp j t + scheduled_at sched_susp j t. *)
@@ 621,15 +618,14 @@ Module ReductionToBasicSchedule.
Proof.
have COMPNEW := reduction_inductive_step_j_hp_completed_in_new.
rename H_induction_hypothesis into IHt.
 rewrite /completed_by eqn_leq; apply/andP; split;
 first by apply cumulative_service_le_job_cost.
+ rewrite /completed_by.
rewrite (leq_add2r (total_suspension original_job_cost next_suspension j_hp)).
rewrite /(inflated_job_cost _).
 apply leq_trans with (n := job_service_without_suspensions j_hp t);
 first by apply eq_leq; symmetry; apply/eqP; apply COMPNEW.
+ apply leq_trans with (n := job_service_without_suspensions j_hp t).
+ apply COMPNEW.
feed (IHt j_hp); first by done.
apply: (leq_trans IHt).
 by rewrite leq_add2l; apply cumulative_suspension_le_total_suspension.
+ by rewrite leq_add2l; apply cumulative_suspension_le_total_suspension.
Qed.
(* ...which of course is a contradiction, since we assumed that j_hp was scheduled
@@ 707,13 +703,12 @@ Module ReductionToBasicSchedule.
have COMP := sched_new_completed_jobs_dont_execute.
have SERV := suspension_oblivious_preserves_service.
intros j t ARRj COMPLETED.
 rewrite /completed_by eqn_leq; apply/andP; split;
 first by apply cumulative_service_le_job_cost.
+ unfold completed_by in *.
rewrite (leq_add2r (total_suspension original_job_cost next_suspension j)).
rewrite /(inflated_job_cost j).
 move: COMPLETED => /eqP EQ; rewrite EQ.
+ apply leq_trans with (service sched_new j t); first by done.
apply: (leq_trans (SERV j t ARRj)); rewrite leq_add2l.
 by apply cumulative_suspension_le_total_suspension.
+ by apply cumulative_suspension_le_total_suspension.
Qed.
End Service.
diff git a/analysis/uni/susp/sustainability/allcosts/main_claim.v b/analysis/uni/susp/sustainability/allcosts/main_claim.v
new file mode 100644
index 0000000000000000000000000000000000000000..44d78e7ee59b74143fca70654e2fc64300b0a7aa
 /dev/null
+++ b/analysis/uni/susp/sustainability/allcosts/main_claim.v
@@ 0,0 +1,165 @@
+Require Import rt.util.all.
+Require Import rt.model.priority rt.model.suspension.
+Require Import rt.model.arrival.basic.arrival_sequence.
+Require Import rt.model.schedule.uni.response_time
+ rt.model.schedule.uni.sustainability.
+Require Import rt.model.schedule.uni.susp.suspension_intervals
+ rt.model.schedule.uni.susp.schedule
+ rt.model.schedule.uni.susp.valid_schedule
+ rt.model.schedule.uni.susp.build_suspension_table
+ rt.model.schedule.uni.susp.platform.
+Require Import rt.analysis.uni.susp.sustainability.allcosts.reduction
+ rt.analysis.uni.susp.sustainability.allcosts.reduction_properties.
+Require Import rt.model.schedule.uni.transformation.construction.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(* In this file, we use the reduction we derived to show the weak sustainability with
+ job costs and varying suspension times in the dynamic suspension model. *)
+Module SustainabilityAllCostsProperty.
+
+ Import ScheduleWithSuspensions Suspension Priority SuspensionIntervals
+ PlatformWithSuspensions ResponseTime Sustainability
+ ValidSuspensionAwareSchedule.
+
+ Module reduction := SustainabilityAllCosts.
+ Module reduction_prop := SustainabilityAllCostsProperties.
+
+ Section SustainabilityProperty.
+
+ Context {Task: eqType}.
+ Context {Job: eqType}.
+
+ (** Defining the task model *)
+
+ Variable higher_eq_priority: JLDP_policy Job.
+ Hypothesis H_priority_reflexive: JLDP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_transitive: JLDP_is_transitive higher_eq_priority.
+
+ Variable job_task: Job > Task.
+ Variable task_suspension_bound: Task > duration.
+
+ (* First, we state all properties about suspension, ... *)
+ Let satisfies_suspension_properties (params: seq (job_parameter Job)) :=
+ dynamic_suspension_model (return_param JOB_COST params) job_task
+ (return_param JOB_SUSPENSION params) task_suspension_bound.
+
+ (* ...all properties of the schedule, ... *)
+ Let satisfies_schedule_properties (params: seq (job_parameter Job)) (arr_seq: arrival_sequence Job)
+ (sched: schedule Job) :=
+ let job_arrival := return_param JOB_ARRIVAL params in
+ let job_cost := return_param JOB_COST params in
+ let job_suspension_duration := return_param JOB_SUSPENSION params in
+ jobs_come_from_arrival_sequence sched arr_seq /\
+ jobs_must_arrive_to_execute job_arrival sched /\
+ completed_jobs_dont_execute job_cost sched /\
+ work_conserving job_arrival job_cost job_suspension_duration arr_seq sched /\
+ respects_JLDP_policy job_arrival job_cost job_suspension_duration arr_seq
+ sched higher_eq_priority /\
+ respects_self_suspensions job_arrival job_cost job_suspension_duration sched.
+
+ (* ...and all properties of the arrival sequence. *)
+ Let satisfies_arrival_sequence_properties (params: seq (job_parameter Job))
+ (arr_seq: arrival_sequence Job) :=
+ arrival_times_are_consistent (return_param JOB_ARRIVAL params) arr_seq /\
+ JLDP_is_total arr_seq higher_eq_priority.
+
+ (* Then, we define the task model as the combination of such properties. *)
+ Let belongs_to_task_model (params: seq (job_parameter Job))
+ (arr_seq: arrival_sequence Job) (sched: schedule Job) :=
+ satisfies_arrival_sequence_properties params arr_seq /\
+ satisfies_schedule_properties params arr_seq sched /\
+ satisfies_suspension_properties params.
+
+ (** Sustainability Claim *)
+
+ (* We use as schedulability property the notion of responsetime bound, i.e., we are
+ going to show that improving job parameters leads to "no worse response times". *)
+ Variable R: time.
+ Let response_time_bounded_by_R (params: seq (job_parameter Job)) (sched: schedule Job) (j: Job) :=
+ is_response_time_bound_of_job (return_param JOB_ARRIVAL params)
+ (return_param JOB_COST params) sched j R.
+
+ (* Next, we recall the definition of weaklysustainable policy with job costs
+ and varying suspension times... *)
+ Let all_params := [:: JOB_ARRIVAL; JOB_COST; JOB_SUSPENSION].
+ Let sustainable_param := JOB_COST.
+ Let variable_params := [:: JOB_SUSPENSION].
+ Let has_better_sustainable_param (cost cost': Job > time) := forall j, cost j >= cost' j.
+
+ Let weakly_sustainable_with_job_costs_and_variable_suspension_times :=
+ weakly_sustainable all_params response_time_bounded_by_R belongs_to_task_model
+ sustainable_param has_better_sustainable_param variable_params.
+
+ (* ...and prove that it holds for this scheduling policy and task model. *)
+ Theorem policy_is_weakly_sustainable:
+ weakly_sustainable_with_job_costs_and_variable_suspension_times.
+ Proof.
+ intros params good_params CONS CONS' ONLY BETTER VSCHED good_arr_seq good_sched good_j BELONGS.
+ split_conj BELONGS; split_conj BELONGS; split_conj BELONGS0; split_conj BELONGS1.
+ set job_arrival := return_param JOB_ARRIVAL good_params.
+ unfold differ_only_by in *.
+ have EQarr: job_arrival = return_param JOB_ARRIVAL params.
+ {
+ move: CONS CONS' => [UNIQ [IFF _]] [UNIQ' [IFF' _]].
+ have ARR: JOB_ARRIVAL \in labels_of params by apply IFF.
+ have ARR': JOB_ARRIVAL \in labels_of good_params by apply IFF'.
+ move: ARR ARR' => /mapP2 [p IN EQ] => /mapP2 [p' IN' EQ'].
+ symmetry in EQ; symmetry in EQ'.
+ have EQp := found_param_label params p JOB_ARRIVAL UNIQ IN EQ.
+ have EQp' := found_param_label good_params p' JOB_ARRIVAL UNIQ' IN' EQ'.
+ specialize (ONLY p p' IN IN').
+ feed_n 2 ONLY; [by rewrite EQ  by rewrite EQ ].
+ rewrite ONLY EQp' in EQp.
+ by inversion EQp.
+ }
+ set good_cost := return_param JOB_COST good_params.
+ set bad_cost := return_param JOB_COST params.
+ set good_suspension := return_param JOB_SUSPENSION good_params.
+ set bad_sched := reduction.sched_new job_arrival good_cost good_arr_seq higher_eq_priority
+ good_sched bad_cost good_j R.
+ set reduced_suspension_duration := reduction.reduced_suspension_duration job_arrival good_cost
+ good_arr_seq higher_eq_priority good_sched good_suspension bad_cost good_j R.
+ set bad_params := [:: param JOB_ARRIVAL job_arrival; param JOB_COST bad_cost;
+ param JOB_SUSPENSION reduced_suspension_duration].
+ apply reduction_prop.sched_new_response_time_of_job_j with (arr_seq := good_arr_seq)
+ (higher_eq_priority0 := higher_eq_priority) (inflated_job_cost := bad_cost);
+ try done.
+ feed (VSCHED bad_params).
+ {
+ split; first by done.
+ split; first by intros l; split;
+ move => IN; rewrite /= 2!in_cons mem_seq1 in IN;
+ move: IN => /orP [/eqP EQ  /orP [/eqP EQ  /eqP EQ]]; rewrite EQ.
+ intros l IN; move: CONS => [_ [IFF CONS]].
+ specialize (CONS l IN); apply IFF in CONS.
+ rewrite 2!in_cons mem_seq1 in CONS.
+ by move: CONS => /orP [/eqP EQ  /orP [/eqP EQ  /eqP EQ]]; rewrite EQ.
+ }
+ rewrite /bad_sched.
+ apply VSCHED with (arr_seq := good_arr_seq).
+ {
+ intros P1 P2 IN1 IN2 EQ NOTIN; simpl in IN2.
+ move: CONS CONS' => [UNIQ _] [UNIQ' [IN' _]].
+ move: IN2 => [EQ2a  [EQ2c  [EQ2s  BUG]]]; try done; first last.
+  by rewrite EQ EQ2s in NOTIN.
+  by rewrite EQ2c; apply found_param_label; rewrite // EQ EQ2c.
+  by rewrite EQ2a EQarr; apply found_param_label; rewrite // EQ EQ2a.
+ }
+ {
+ repeat split; try (by done).
+  by apply reduction_prop.sched_new_jobs_come_from_arrival_sequence.
+  by apply reduction_prop.sched_new_jobs_must_arrive_to_execute.
+  by apply reduction_prop.sched_new_completed_jobs_dont_execute.
+  by apply reduction_prop.sched_new_work_conserving.
+  by apply reduction_prop.sched_new_respects_policy.
+  by apply reduction_prop.sched_new_respects_self_suspensions.
+ intros j0.
+ apply leq_trans with (n := total_suspension good_cost good_suspension j0); last by done.
+ by apply reduction_prop.sched_new_has_shorter_total_suspension.
+ }
+ Qed.
+
+ End SustainabilityProperty.
+
+End SustainabilityAllCostsProperty.
\ No newline at end of file
diff git a/analysis/uni/susp/sustainability/allcosts/reduction_properties.v b/analysis/uni/susp/sustainability/allcosts/reduction_properties.v
index 506e5b834048149933c88160215fb9691cb10fc9..19420efb329930ce7b6316818076e7569ed9fa6f 100644
 a/analysis/uni/susp/sustainability/allcosts/reduction_properties.v
+++ b/analysis/uni/susp/sustainability/allcosts/reduction_properties.v
@@ 24,7 +24,6 @@ Module SustainabilityAllCostsProperties.
Section ReductionProperties.
 Context {Task: eqType}.
Context {Job: eqType}.
Variable job_arrival: Job > time.
Variable job_cost: Job > time.
@@ 233,19 +232,17 @@ Module SustainabilityAllCostsProperties.
/reduction.build_schedule.
case: (_ < _); rewrite /reduction.highest_priority_job
/reduction.highest_priority_late_job.
 {
 apply/eqP; intro SCHEDn.
+ { apply/eqP; intro SCHEDn.
apply seq_min_in_seq in SCHEDn.
rewrite mem_filter in SCHEDn.
move: SCHEDn => /andP [/andP [/andP [_ NOTCOMP] _] _].
 by rewrite /completed_by EQ eq_refl in NOTCOMP.
+ by rewrite /completed_by EQ leqnn in NOTCOMP.
}
 {
 apply/eqP; intro SCHEDn.
+ { apply/eqP; intro SCHEDn.
apply seq_min_in_seq in SCHEDn.
rewrite mem_filter in SCHEDn.
move: SCHEDn => /andP [/andP [_ NOTCOMP] _].
 by rewrite /completed_by EQ eq_refl in NOTCOMP.
+ by rewrite /completed_by EQ leqnn in NOTCOMP.
}
Qed.
@@ 315,12 +312,11 @@ Module SustainabilityAllCostsProperties.
completed_by job_cost sched_susp any_j t.
Proof.
intros j0 COMPn.
 rewrite /completed_by eqn_leq; apply/andP; split;
 first by apply cumulative_service_le_job_cost.
+ unfold completed_by in *.
rewrite (leq_add2r (inflated_job_cost j0  job_cost j0)).
rewrite subnKC; last by eauto 1.
 move: COMPn => /eqP {1}<.
 by apply sched_new_service_invariant.
+ apply leq_trans with (service sched_new j0 t); first by done.
+ by apply sched_new_service_invariant.
Qed.
End ServiceInvariant.
@@ 392,7 +388,7 @@ Module SustainabilityAllCostsProperties.
have SAME: service sched_new j0 t.+1 = service sched_new j0 t.
{
apply negbTE in NOTSCHEDn.
 by rewrite /service /service_during big_nat_recr //= /service_at NOTSCHEDn.
+ by rewrite /service /service_during big_nat_recr //= /service_at NOTSCHEDn addn0.
}
rewrite SAME {SAME} in NOTLATE'.
have INV := sched_new_service_invariant t (ltnW LTr) j0.
@@ 521,7 +517,7 @@ Module SustainabilityAllCostsProperties.
apply leq_trans with (n := suspension_start sched_susp j0 t); [by apply IHt].
apply eq_leq, same_service_implies_same_last_execution.
rewrite /service /service_during big_nat_recr //= /service_at.
 case (boolP (scheduled_at sched_susp j0 t)); last by done.
+ case (boolP (scheduled_at sched_susp j0 t)); last by rewrite addn0.
intros SCHEDs; apply H_respects_self_suspensions in SCHEDs.
by move: SUSPn => /andP [/andP [_ SUSPs] _].
}
@@ 577,7 +573,7 @@ Module SustainabilityAllCostsProperties.
apply/negP; intro COMPmid.
apply suspended_implies_not_completed in SUSPt.
suff BUG: completed_by job_cost sched_susp j0 t by rewrite BUG in SUSPt.
 by apply completion_monotonic with (t0 := k); [ by apply ltnW ].
+ by apply completion_monotonic with (t0 := k); [ apply ltnW ].
}
apply/andP; split;
last by apply: (ltn_trans LT); move: SUSPt => /andP [_ /andP [_ GTt]].
@@ 638,9 +634,9 @@ Module SustainabilityAllCostsProperties.
Let cumulative_suspension_in_sched_new :=
cumulative_suspension job_arrival inflated_job_cost reduced_suspension_duration sched_new.
 (* To conclude, we prove that the suspension durations in the new schedule are no
 longer than in the original schedule. *)
 Lemma sched_new_has_shorter_suspensions:
+ (* To conclude, we prove that the cumulative suspension in the new schedule is no
+ larger than in the original schedule,... *)
+ Lemma sched_new_has_shorter_suspension:
forall any_j t,
cumulative_suspension_in_sched_new any_j t
<= cumulative_suspension_in_sched_susp any_j t.
@@ 665,6 +661,57 @@ Module SustainabilityAllCostsProperties.
}
Qed.
+ (* ... which implies that the total suspension is also no larger. *)
+ Corollary sched_new_has_shorter_total_suspension:
+ forall any_j,
+ total_suspension inflated_job_cost reduced_suspension_duration any_j <=
+ total_suspension job_cost job_suspension_duration any_j.
+ Proof.
+ intros any_j.
+ apply leq_trans with (n := cumulative_suspension_in_sched_new any_j (arr_j + R)).
+ {
+ unfold total_suspension, reduced_suspension_duration, reduction.reduced_suspension_duration,
+ build_suspension_duration.
+ rewrite /sched_new.
+ set SUSP_new := _ job_arrival job_cost _ _ _ _ _ _ _.
+ set cost' := inflated_job_cost.
+ set arr := job_arrival j.
+ apply leq_trans with (n := \sum_(0 <= t < cost' any_j) \sum_(0 <= t0 < arr + R)
+ if (service sched_new any_j t0 == t) then SUSP_new any_j t0 else false);
+ first by apply leq_sum; ins; rewrite big_mkcond; apply leq_sum; ins; case: (_ == _).
+ rewrite exchange_big /=.
+ apply leq_sum_nat; move => i /= LT _.
+ case COMP: (completed_in_sched_new any_j i).
+ { apply leq_trans with 0; last by done.
+ rewrite big_nat_cond big1 //; move => s /= LTs.
+ case EQ: (_ == _); last by done.
+ move: EQ => /eqP EQ; rewrite andbT EQ {EQ} in LTs.
+ by exfalso; move: LTs; rewrite ltnNge; move => /negP LTs; apply: LTs.
+ }
+ { apply negbT in COMP; rewrite ltnNge in COMP.
+ set s := service sched_new any_j i; rewrite /s in COMP.
+ rewrite > big_cat_nat with (n := s); [simpl  by done  by apply ltnW].
+ rewrite > big_cat_nat with (m := s) (n := s.+1); [simpl  by done  by done].
+ rewrite big_nat_cond big1; last first.
+ {
+ move => i0; rewrite andbT; move => /= LT0.
+ by case EQ: (_ == _) => //; move: EQ => /eqP EQ; subst; rewrite ltnn in LT0.
+ }
+ rewrite add0n big_nat_recr //= eq_refl big_geq // add0n.
+ rewrite big_nat_cond big1; [rewrite addn0 ]; last first.
+ {
+ move => i0; rewrite andbT; move => /andP [LT0 _].
+ rewrite ltn_neqAle in LT0; move: LT0 => /andP [NEQ _].
+ by apply negbTE in NEQ; rewrite NEQ.
+ }
+ by rewrite sched_new_suspension_matches.
+ }
+ }
+ apply leq_trans with (n := cumulative_suspension_in_sched_susp any_j (arr_j + R));
+ first by apply sched_new_has_shorter_suspension.
+ by apply cumulative_suspension_le_total_suspension.
+ Qed.
+
End SuspensionTable.
(** SuspensionRelated Schedule Properties *)
@@ 732,24 +779,20 @@ Module SustainabilityAllCostsProperties.
have IN0: j0 \in jobs_arrived_up_to arr_seq t.
by eapply arrived_between_implies_in_arrivals; eauto 1.
move: NOTSUSP => /orP [NOTSUSPs  LT]; last first.
 {
 clear SCHEDn; apply seq_min_exists with (x := j0).
 by rewrite mem_filter PEND IN0 andbT LT.
+ { clear SCHEDn; apply seq_min_exists with (x := j0).
+ by rewrite mem_filter PEND IN0 andbT LT.
}
case (boolP (completed_by job_cost sched_susp j0 t)) => [COMPs  NOTCOMPs].
 {
 clear SCHEDn; apply seq_min_exists with (x := j0).
+ { clear SCHEDn; apply seq_min_exists with (x := j0).
rewrite mem_filter PEND IN0 andbT /=.
apply/orP; left.
apply leq_trans with (n := job_cost j0 + (inflated_job_cost j0  job_cost j0));
 last by move: COMPs => /eqP <; rewrite leq_add2r.
+ last by rewrite leq_add2r.
rewrite subnKC; last by apply H_job_costs_do_not_decrease.
 by rewrite ltn_neqAle; apply/andP; split;
 last by apply sched_new_completed_jobs_dont_execute.
+ by rewrite ltnNge.
}
case (boolP (scheduled_at sched_susp j0 t)) => [SCHEDs  NOTSCHEDs].
 {
 clear SCHEDn; apply seq_min_exists with (x := j0).
+ { clear SCHEDn; apply seq_min_exists with (x := j0).
by rewrite mem_filter PEND IN0 andbT SCHEDs orbT.
}
feed (WORKs j0 t IN); first by repeat (apply/andP; split).
@@ 829,11 +872,10 @@ Module SustainabilityAllCostsProperties.
rewrite mem_filter PEND /= IN1 andbT.
apply/orP; left.
rewrite /reduction.job_is_late.
 move: COMPs => /eqP >; rewrite subnKC; last by eauto 1.
+ apply leq_trans with (job_cost j1 + (inflated_job_cost j1  job_cost j1)); last by rewrite leq_add2r.
+ rewrite subnKC; last by eauto 1.
move: PEND => /andP [_ NOTCOMP].
 rewrite ltn_neqAle; apply/andP; split; first by done.
 apply cumulative_service_le_job_cost.
 by apply sched_new_completed_jobs_dont_execute.
+ by rewrite ltnNge.
}
feed (WORKs j1 t ARRin); first by repeat (apply/andP; split).
move: WORKs => [j_hp SCHEDhp].
@@ 888,4 +930,4 @@ Module SustainabilityAllCostsProperties.
End ReductionProperties.
End SustainabilityAllCostsProperties.
\ No newline at end of file
+End SustainabilityAllCostsProperties.
diff git a/analysis/uni/susp/sustainability/singlecost/reduction_properties.v b/analysis/uni/susp/sustainability/singlecost/reduction_properties.v
index 1389856cccc85c478ac19e486c2f5c2a74b03f6e..724974ca172c5873b283612dcf8516b1cf5b9180 100644
 a/analysis/uni/susp/sustainability/singlecost/reduction_properties.v
+++ b/analysis/uni/susp/sustainability/singlecost/reduction_properties.v
@@ 267,17 +267,15 @@ Module SustainabilitySingleCostProperties.
by eapply in_arrivals_implies_arrived_before in IN; eauto.
}
destruct (sched_susp t) eqn:SCHEDs; last first.
 {
 apply/eqP; case => SAME; subst j0.
+ { apply/eqP; case => SAME; subst j0.
suff NOTPEND: ~~ pending job_arrival inflated_job_cost sched_susp_highercost j_hp t.
 by rewrite PENDhp in NOTPEND.
 by rewrite /pending negb_and; apply/orP; right; rewrite negbK; apply/eqP.
+  by rewrite PENDhp in NOTPEND.
+  by rewrite /pending negb_and; apply/orP; right; rewrite negbK /completed_by EQ.
}
 {
 case: ifP => [PEND  NOTPEND]; apply/eqP; case => SAME; subst j0;
 last by move: PENDhp => /andP [_ NC]; rewrite /completed_by EQ eq_refl in NC.
+ { case: ifP => [PEND  NOTPEND]; apply/eqP; case => SAME; subst j0;
+ last by move: PENDhp => /andP [_ NC]; rewrite /completed_by EQ leqnn in NC.
move: PEND => /andP [/andP [/andP [_ NC] _] _].
 by rewrite /completed_by EQ eq_refl in NC.
+ by rewrite /completed_by EQ leqnn in NC.
}
Qed.
@@ 409,27 +407,25 @@ Module SustainabilitySingleCostProperties.
H_inflation_only_for_job_j into COSTother.
have COMPLETIONw := sched_susp_highercost_completed_jobs_dont_execute.
rewrite /completed_in_sched_susp/completed_in_sched_susp_highercost
 /completed_by in NOTCOMPj *.
+ /completed_by ltnNge in NOTCOMPj *.
intros any_j; apply/idP/idP.
 {
 intros COMPs.
+ { intros COMPs.
case (boolP (any_j == j)) => [/eqP EQ  NEQ]; subst.
 {
 suff BUG: service sched_susp j t == job_cost j by rewrite BUG in NOTCOMPj.
 by apply completion_monotonic with (t0 := k); try (by done); apply ltnW.
+ { unfold completed_jobs_dont_execute in *.
+ have BUG: service sched_susp j t >= job_cost j.
+ { apply completion_monotonic with (t0 := k); try (by done); apply ltnW. }
+ by exfalso; move: BUG; rewrite leqNgt; move => /negP BUG; apply: BUG.
}
 rewrite COSTother //; move: COMPs => /eqP <.
 apply/eqP; rewrite /service /service_during big_nat_cond [X in _=X]big_nat_cond.
 apply eq_bigr; move => i /= /andP [LT _].
 by rewrite /service_at IH //; apply: (leq_trans LT).
+ rewrite COSTother //.
+ apply leq_trans with (service sched_susp any_j k); first by done.
+ rewrite /service /service_during big_nat_cond [X in _ <= X]big_nat_cond.
+ rewrite leq_sum //; move => i /= /andP [LT _].
+ by rewrite /service_at IH //; apply: (leq_trans LT).
}
 {
 intros COMPw.
 rewrite eqn_leq; apply/andP; split;
 first by apply cumulative_service_le_job_cost.
+ { intros COMPw.
apply leq_trans with (n := inflated_job_cost any_j);
first by case (boolP (any_j==j)) => [/eqP EQ  NEQ]; subst; rewrite ?COSTj ?COSTother.
 move: COMPw => /eqP <.
+ apply leq_trans with (service sched_susp_highercost any_j k); first by done.
apply leq_sum_nat; move => i /= LT _.
by rewrite /service_at IH //; apply: (leq_trans LT).
}
@@ 593,7 +589,7 @@ Module SustainabilitySingleCostProperties.
intros k any_j LT; apply IHtmp; first by done.
apply/negP; intro COMPk.
suff COMPt: completed_in_sched_susp j t by rewrite COMPt in NOTCOMP.
 by apply completion_monotonic with (t0 := k); [ apply ltnW].
+ by apply completion_monotonic with (t0 := k);[apply ltnW].
Qed.
End SchedulingInvariant.
@@ 638,17 +634,16 @@ Module SustainabilitySingleCostProperties.
apply/negP; intro COMPt.
suff BUG: t >= arr_j + r by rewrite leqNgt LT in BUG.
have AFTER: arr_j <= t.
 {
 apply contraT; rewrite ltnNge; intro BEFORE.
+ { apply contraT; rewrite ltnNge; intro BEFORE.
suff BUG: ~~ completed_in_sched_susp j t by rewrite COMPt in BUG.
rewrite /completed_in_sched_susp /completed_by /service /service_during.
rewrite (cumulative_service_before_job_arrival_zero job_arrival) //; last by apply ltnW.
 by rewrite eq_sym lt0n.
+ by rewrite ltnNge.
}
rewrite [t](addKn arr_j) addnBA //.
rewrite leq_add2l; apply TIGHT.
rewrite /job_response_time_in_sched_susp_bounded_by /is_response_time_bound_of_job.
 by rewrite subnKC.
+ by rewrite subnKC.
Qed.
(* Next, since r is an exact response time bound, we show that r <= R... *)
@@ 665,8 +660,13 @@ Module SustainabilitySingleCostProperties.
set Sw := service_during sched_susp_highercost in RESPw RESPs TIGHT SAME.
set Ss := service_during sched_susp in RESPs TIGHT SAME.
apply contraT; rewrite ltnNge; intros LT.
+ have RESPs': job_cost j == Ss j 0 (job_arrival j + r).
+ { rewrite eqn_leq; apply/andP; split; try done.
+ by apply H_completed_jobs_dont_execute.
+ }
suff BUG: job_cost j > inflated_job_cost j by rewrite ltnNge COSTj in BUG.
 move: RESPw RESPs => /eqP RESPw /eqP RESPs; rewrite RESPw RESPs.
+ move: RESPs RESPs' => _ /eqP RESPs; rewrite RESPs.
+ apply leq_ltn_trans with (Sw j 0 (job_arrival j + R)); first by done.
rewrite /Ss /service_during.
rewrite > big_cat_nat with (n := arr_j + R);
[simpl  by done  by rewrite leq_add2l ltnW].
@@ 675,16 +675,15 @@ Module SustainabilitySingleCostProperties.
rewrite lt0n; apply/eqP; intro ZERO.
suff BUG: R >= r by rewrite leqNgt LT in BUG.
apply TIGHT.
 rewrite (eqn_add2r 0) {2}ZERO addn0.
+ rewrite (leq_add2r 0) {3}ZERO addn0.
rewrite big_cat_nat //=; last by rewrite leq_add2l ltnW.
 by rewrite RESPs.
+ by rewrite RESPs.
Qed.
(* ...and also prove that R must be as large as the inflated job cost. *)
Lemma R_bounds_inflated_cost: R >= inflated_job_cost j.
Proof.
 apply leq_trans with (n := service sched_susp_highercost j (arr_j + R));
 first by apply eq_leq; symmetry; apply/eqP.
+ apply leq_trans with (n := service sched_susp_highercost j (arr_j + R)); first by done.
rewrite /service /service_during.
rewrite (ignore_service_before_arrival job_arrival) //; first last.
 by apply leq_addr.
@@ 704,9 +703,9 @@ Module SustainabilitySingleCostProperties.
H_response_time_bound_in_sched_susp_highercost into RESPw.
rewrite leq_subLR.
rewrite addnBA; last by apply GECOST.
 apply leq_trans with (n := service_in_sched_susp j (arr_j + r) + R
  service_in_sched_susp_highercost j (arr_j + R));
 last by apply leq_sub; [rewrite leq_add2r]; apply eq_leq; [symmetry]; apply/eqP.
+ apply leq_trans with
+ (n := service_in_sched_susp j (arr_j + r) + R  service_in_sched_susp_highercost j (arr_j + R));
+ last by rewrite leq_sub // leq_add2r.
rewrite addnC.
rewrite /service_in_sched_susp /service_in_sched_susp_highercost /service
/service_during in SAME *.
@@ 722,16 +721,10 @@ Module SustainabilitySingleCostProperties.
rewrite addnC addnBA; last by rewrite SAME.
apply leq_trans with (n := R  (Sw j (arr_j + r) (arr_j + R) + 0));
last by rewrite leq_sub2l // leq_add2l; apply eq_leq; apply/eqP; rewrite subn_eq0 SAME.
 rewrite addn0 subh3 //; last first.
 {
 apply leq_trans with (n := Sw j arr_j (arr_j+R)); last by apply cumulative_service_le_delta.
 by apply extend_sum; first by apply leq_addr.
 }
 {
 apply leq_trans with (n := r + \sum_(arr_j+r<=t /andP [_ /negP HP].
 by apply HP, order_sorted_rcons with (s := l'); try by done.
+ by apply HP, order_sorted_rcons with (xs := l'); try by done.
}
move: (IHl cpu CAN) => [j_old IN]; clear IHl LAST.
by eapply replace_first_previous in IN; des;
@@ 467,7 +467,7 @@ Module ConcreteScheduler.
}
{
subst j_last.
 by apply order_sorted_rcons with (s := l').
+ by apply order_sorted_rcons with (xs := l').
}
{
subst j_last; clear IHl.
@@ 485,7 +485,7 @@ Module ConcreteScheduler.
move: SHOULD => /andP [CAN' /negP HP].
unfold prev in IN'.
apply scheduler_job_in_mapping in IN'.
 by exfalso; apply HP, order_sorted_rcons with (s := l').
+ by exfalso; apply HP, order_sorted_rcons with (xs := l').
}
{
destruct [exists cpu, ((cpu, Some j) \in prev)] eqn:EX.
@@ 497,7 +497,7 @@ Module ConcreteScheduler.
in IN''; des;
first by specialize (NOTSCHED cpu'); rewrite IN'' in NOTSCHED.
move: IN'' => /andP [_ /negP HP].
 by exfalso; apply HP, order_sorted_rcons with (s := l').
+ by exfalso; apply HP, order_sorted_rcons with (xs := l').
}
{
apply negbT in EX; rewrite negb_exists in EX.
@@ 529,7 +529,7 @@ Module ConcreteScheduler.
}
{
move: BUG => /andP [_ /negP HP].
 by apply HP, order_sorted_rcons with (s := l'); try by done.
+ by apply HP, order_sorted_rcons with (xs := l'); try by done.
}
}
{
@@ 611,7 +611,7 @@ Module ConcreteScheduler.
apply scheduler_job_in_mapping in SCHED.
rewrite mem_sort mem_filter in SCHED.
move: SCHED => /andP [/andP [_ NOTCOMP] _].
 by rewrite /completed EQ eq_refl in NOTCOMP.
+ by rewrite /completed EQ leqnn in NOTCOMP.
Qed.
(* In addition, the scheduler is APA work conserving, ... *)
diff git a/implementation/global/basic/schedule.v b/implementation/global/basic/schedule.v
index 9e8eded3f44192d46de4aa95bf3f5c3406df83e4..49a86fabf74525ef07cfb490e932f1c19ed3eeb6 100644
 a/implementation/global/basic/schedule.v
+++ b/implementation/global/basic/schedule.v
@@ 221,7 +221,7 @@ Module ConcreteScheduler.
apply nth_or_none_mem in SCHED.
rewrite mem_sort mem_filter in SCHED.
move: SCHED => /andP [/andP [_ NOTCOMP] _].
 by rewrite /completed EQ eq_refl in NOTCOMP.
+ by rewrite /completed EQ leqnn in NOTCOMP.
Qed.
(* In addition, the scheduler is work conserving, ... *)
diff git a/implementation/global/jitter/schedule.v b/implementation/global/jitter/schedule.v
index 47ab16a7ce84d23a6a086faf50b29c641e6936ad..d8e1ff972b47428f27d89f455a306afd7779bbae 100644
 a/implementation/global/jitter/schedule.v
+++ b/implementation/global/jitter/schedule.v
@@ 226,7 +226,7 @@ Module ConcreteScheduler.
apply nth_or_none_mem in SCHED.
rewrite mem_sort mem_filter in SCHED.
move: SCHED => /andP [/andP [_ NOTCOMP] _].
 by rewrite /completed EQ eq_refl in NOTCOMP.
+ by rewrite /completed EQ leqnn in NOTCOMP.
Qed.
(* In addition, the scheduler is (jitteraware) work conserving, ... *)
diff git a/implementation/uni/basic/schedule.v b/implementation/uni/basic/schedule.v
index 742c5d25dee6f0c89aca2cb049bb3fac68dae6ab..3f7bdbdd00da7a6bb873131995b3a921b4452e8e 100644
 a/implementation/uni/basic/schedule.v
+++ b/implementation/uni/basic/schedule.v
@@ 146,7 +146,7 @@ Module ConcreteScheduler.
rewrite /highest_priority_job.
apply/eqP; intro HP.
apply seq_min_in_seq in HP.
 by rewrite mem_filter /pending /completed_by EQ eq_refl andbF andFb in HP.
+ by rewrite mem_filter /pending /completed_by EQ /sched leqnn andbF andFb in HP.
Qed.
(* In addition, the scheduler is work conserving, ... *)
diff git a/implementation/uni/basic/schedule_tdma.v b/implementation/uni/basic/schedule_tdma.v
index c9ba2b9cac275ecfc1ca57c05c112b0b47e000d5..097c6bc880829e69795ade929589859c9fe54ef6 100644
 a/implementation/uni/basic/schedule_tdma.v
+++ b/implementation/uni/basic/schedule_tdma.v
@@ 221,7 +221,7 @@ Module ConcreteSchedulerTDMA.
rewrite /job_to_schedule.
apply/eqP; intro FIND.
apply findP_in_seq in FIND. move:FIND => [IN PEN].
 by rewrite mem_filter /pending /completed_by EQ eq_refl andbF andFb in PEN.
+ by rewrite mem_filter /pending /completed_by EQ leqnn andbF andFb in PEN.
Qed.
End ImplementationTDMA.
diff git a/implementation/uni/jitter/schedule.v b/implementation/uni/jitter/schedule.v
index d4581e2c0bb4660dee1351d234e82b8bd22ab3c0..8f410279a36be8bfcfb47a82e07b2f9d4ab51f0e 100644
 a/implementation/uni/jitter/schedule.v
+++ b/implementation/uni/jitter/schedule.v
@@ 148,7 +148,7 @@ Module ConcreteScheduler.
rewrite /sched scheduler_uses_construction_function /highest_priority_job.
apply/eqP; intro HP.
apply seq_min_in_seq in HP.
 by rewrite mem_filter /pending /completed_by EQ eq_refl andbF /= in HP.
+ by rewrite mem_filter /pending /completed_by EQ leqnn andbF /= in HP.
Qed.
(* In addition, the scheduler is work conserving... *)
diff git a/implementation/uni/susp/schedule.v b/implementation/uni/susp/schedule.v
index bdcdc0eefa427ff8e7dc3966a323e7b92666a64f..cf1c7138ab5b8ba4d97e673bd010b69468be6d91 100644
 a/implementation/uni/susp/schedule.v
+++ b/implementation/uni/susp/schedule.v
@@ 195,7 +195,7 @@ Module ConcreteScheduler.
rewrite /highest_priority_job.
apply/eqP; intro HP.
apply seq_min_in_seq in HP.
 by rewrite mem_filter /pending /completed_by EQ eq_refl andbF 2!andFb in HP.
+ by rewrite mem_filter /pending /completed_by EQ leqnn andbF 2!andFb in HP.
Qed.
(* In addition, the scheduler is work conserving, ... *)
diff git a/model/arrival/basic/arrival_bounds.v b/model/arrival/basic/arrival_bounds.v
index 1f7797bbc414189b28e6e633c2bbf9bd9521053c..8bee5cd0217a7a7414813b2dcf6318ca18d613b0 100644
 a/model/arrival/basic/arrival_bounds.v
+++ b/model/arrival/basic/arrival_bounds.v
@@ 1,13 +1,12 @@
Require Import rt.util.all.
Require Import rt.model.arrival.basic.arrival_sequence rt.model.arrival.basic.task rt.model.arrival.basic.job rt.model.arrival.basic.task_arrival
rt.model.priority.
Require Import rt.model.schedule.uni.basic.busy_interval.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path div.
(* Properties of job arrival. *)
Module ArrivalBounds.
 Import ArrivalSequence SporadicTaskset TaskArrival Priority BusyInterval.
+ Import ArrivalSequence SporadicTaskset TaskArrival Priority.
Section Lemmas.
diff git a/model/arrival/basic/arrival_sequence.v b/model/arrival/basic/arrival_sequence.v
index cc12c8599316b03565f75720ba6550abe44013c8..78e67106d855eb403307f6c7466f5ee45fbeb8e5 100644
 a/model/arrival/basic/arrival_sequence.v
+++ b/model/arrival/basic/arrival_sequence.v
@@ 110,6 +110,16 @@ Module ArrivalSequence.
(* First, we show that the set of arriving jobs can be split
into disjoint intervals. *)
+ Lemma job_arrived_between_cat:
+ forall t1 t t2,
+ t1 <= t >
+ t <= t2 >
+ jobs_arrived_between t1 t2 = jobs_arrived_between t1 t ++ jobs_arrived_between t t2.
+ Proof.
+ unfold jobs_arrived_between; intros t1 t t2 GE LE.
+ by rewrite (@big_cat_nat _ _ _ t).
+ Qed.
+
Lemma jobs_arrived_between_mem_cat:
forall j t1 t t2,
t1 <= t >
@@ 117,28 +127,7 @@ Module ArrivalSequence.
j \in jobs_arrived_between t1 t2 =
(j \in jobs_arrived_between t1 t ++ jobs_arrived_between t t2).
Proof.
 unfold jobs_arrived_between; intros j t1 t t2 GE LE.
 apply/idP/idP.
 {
 intros IN.
 apply mem_bigcat_nat_exists in IN; move: IN => [arr [IN /andP [GE1 LT2]]].
 rewrite mem_cat; apply/orP.
 by destruct (ltnP arr t); [left  right];
 apply mem_bigcat_nat with (j := arr); try (by apply/andP; split).
 }
 {
 rewrite mem_cat; move => /orP [LEFT  RIGHT].
 {
 apply mem_bigcat_nat_exists in LEFT; move: LEFT => [t0 [IN0 /andP [GE0 LT0]]].
 apply mem_bigcat_nat with (j := t0); last by done.
 by rewrite GE0 /=; apply: (leq_trans LT0).
 }
 {
 apply mem_bigcat_nat_exists in RIGHT; move: RIGHT => [t0 [IN0 /andP [GE0 LT0]]].
 apply mem_bigcat_nat with (j := t0); last by done.
 by rewrite LT0 andbT; apply: (leq_trans _ GE0).
 }
 }
+ by intros j t1 t t2 GE LE; rewrite (job_arrived_between_cat _ t).
Qed.
Lemma jobs_arrived_between_sub:
diff git a/model/arrival/basic/job.v b/model/arrival/basic/job.v
index 9fff5b15743ddfc2d8783fb46d61ddb2b0074fb1..d584d8372b83000a9ee9887386704ff2d3018be8 100644
 a/model/arrival/basic/job.v
+++ b/model/arrival/basic/job.v
@@ 1,10 +1,10 @@
Require Import rt.model.time rt.model.arrival.basic.task.
+Require Import rt.model.time rt.model.arrival.basic.task rt.model.arrival.basic.arrival_sequence.
From mathcomp Require Import ssrnat ssrbool eqtype.

+
(* Properties of different types of job: *)
Module Job.
 Import Time.
+ Import Time ArrivalSequence.
(* 1) Basic Job *)
Section ValidJob.
@@ 19,7 +19,7 @@ Module Job.
End ValidJob.
 (* 2) realtime job (with a deadline) *)
+ (* 2) Realtime job (with a deadline) *)
Section ValidRealtimeJob.
Context {Job: eqType}.
@@ 38,7 +38,7 @@ Module Job.
job_deadline_positive.
End ValidRealtimeJob.

+
(* 3) Job of sporadic task *)
Section ValidSporadicTaskJob.
@@ 68,4 +68,26 @@ Module Job.
End ValidSporadicTaskJob.
+ (* 4) Job of task *)
+ Section ValidTaskJob.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* The job cost from the arrival sequence
+ cannot be larger than the task cost. *)
+ Definition cost_of_jobs_from_arrival_sequence_le_task_cost :=
+ forall j,
+ arrives_in arr_seq j >
+ job_cost_le_task_cost task_cost job_cost job_task j.
+
+ End ValidTaskJob.
+
End Job.
\ No newline at end of file
diff git a/model/arrival/basic/task_arrival.v b/model/arrival/basic/task_arrival.v
index d9cb85399a006089a3f8429d358332f0bcde1490..3480dd872870ca0c95cfa38bf7cf6da35690be7d 100644
 a/model/arrival/basic/task_arrival.v
+++ b/model/arrival/basic/task_arrival.v
@@ 1,6 +1,6 @@
Require Import rt.util.all.
Require Import rt.model.arrival.basic.arrival_sequence rt.model.arrival.basic.task rt.model.arrival.basic.job.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path bigop.
(* Properties of job arrival. *)
Module TaskArrival.
@@ 54,11 +54,33 @@ Module TaskArrival.
(* ...we can identify the jobs of tsk that arrived in any interval [t1, t2) ... *)
Definition arrivals_of_task_between (t1 t2: time) :=
[seq j < arrivals_between t1 t2  is_job_of_task j].

+
+ (* ...we define the jobs of tsk that arrived before some time instant t ... *)
+ Definition arrivals_of_task_before (t: time) :=
+ arrivals_of_task_between 0 t.
+
(* ...and also count the number of job arrivals. *)
Definition num_arrivals_of_task (t1 t2: time) :=
size (arrivals_of_task_between t1 t2).
+ (* In this section we prove some basic lemmas about number of arrivals of task. *)
+ Section Lemmas.
+
+ (* We show that the number of arrivals of task can be split into disjoint intervals. *)
+ Lemma num_arrivals_of_task_cat:
+ forall t t1 t2,
+ t1 <= t <= t2 >
+ num_arrivals_of_task t1 t2 = num_arrivals_of_task t1 t + num_arrivals_of_task t t2.
+ Proof.
+ move => t t1 t2 /andP [GE LE].
+ rewrite /num_arrivals_of_task /arrivals_of_task_between
+ /arrivals_between /jobs_arrived_between.
+ rewrite (@big_cat_nat _ _ _ t) //=.
+ by rewrite filter_cat size_cat.
+ Qed.
+
+ End Lemmas.
+
End NumberOfArrivals.
(* In this section, we prove some basic results regarding the
@@ 72,7 +94,7 @@ Module TaskArrival.
Variable job_arrival: Job > time.
Variable job_task: Job > Task.
 (* Consider any arrival sequence with consistent, duplicatefree arrivals, ... *)
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals, ... *)
Variable arr_seq: arrival_sequence Job.
Hypothesis H_consistent_arrivals: arrival_times_are_consistent job_arrival arr_seq.
Hypothesis H_no_duplicate_arrivals: arrival_sequence_is_a_set arr_seq.
diff git a/model/arrival/curves/bounds.v b/model/arrival/curves/bounds.v
new file mode 100644
index 0000000000000000000000000000000000000000..d7a4c0fb7b132b6f02fa76eb60d0a074740f4f6b
 /dev/null
+++ b/model/arrival/curves/bounds.v
@@ 0,0 +1,90 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.arrival_sequence
+ rt.model.arrival.basic.task_arrival.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq div.
+
+(* In this section, we define the notion of arrival curves, which
+ can be used to reason about the frequency of job arrivals. *)
+Module ArrivalCurves.
+
+ Import ArrivalSequence TaskArrival.
+
+ Section DefiningArrivalCurves.
+
+ Context {Task: eqType}.
+ Context {Job: eqType}.
+ Variable job_task: Job > Task.
+
+ (* Consider any job arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* Recall the job arrivals of tsk in a given interval [t1, t2). *)
+ Let arrivals_of_tsk tsk := arrivals_of_task_between job_task arr_seq tsk.
+ Let num_arrivals_of_tsk tsk := num_arrivals_of_task job_task arr_seq tsk.
+
+ (* First, we define what constitutes an arrival bound for task tsk. *)
+ Section ArrivalBound.
+
+ (* Let max_arrivals denote any function that takes an interval length and
+ returns the associated number of job arrivals of task.
+ (This corresponds to the eta+ function in the literature.) *)
+ Variable max_arrivals: Task > time > nat.
+
+ (* Then, we say that max_arrivals is an arrival bound iff, for any interval [t1, t2),
+ [num_arrivals (t2  t1)] bounds the number of jobs of tsk that arrive in that interval. *)
+ Definition is_arrival_bound (tsk: Task) :=
+ forall (t1 t2: time),
+ t1 <= t2 >
+ num_arrivals_of_tsk tsk t1 t2 <= max_arrivals tsk (t2  t1).
+
+ (* We say that max_arrivals is an arrival bound for taskset ts
+ iff max_arrival is an arrival bound for any task from ts. *)
+ Definition is_arrival_bound_for_taskset (ts: seq Task) :=
+ forall (tsk: Task), tsk \in ts > is_arrival_bound tsk.
+
+ (* We provide the notion of an arrival curve that equals 0 for the empty interval. *)
+ Definition zero_arrival_curve (tsk: Task) :=
+ max_arrivals tsk 0 = 0.
+
+ (* Next, we provide the notion of a monotonic arrival curve. *)
+ Definition monotonic_arrival_curve (tsk: Task) :=
+ monotone (max_arrivals tsk) leq.
+
+ (* We say that max_arrivals is a proper arrival curve for task tsk iff
+ [max_arrivals tsk] is an arrival bound for task tsk and [max_arrivals tsk]
+ is a monotonic function that equals 0 for the empty interval delta = 0. *)
+ Definition proper_arrival_curve (tsk: Task) :=
+ is_arrival_bound tsk /\
+ zero_arrival_curve tsk /\
+ monotonic_arrival_curve tsk.
+
+ (* We say that max_arrivals is a family of proper arrival curves iff
+ for all tsk in ts [max_arrival tsk] is a proper arrival curve. *)
+ Definition family_of_proper_arrival_curves (ts: seq Task) :=
+ forall (tsk: Task), tsk \in ts > proper_arrival_curve tsk.
+
+ End ArrivalBound.
+
+ (* Next, we define the notion of a separation bound for task tsk, i.e., the smallest
+ interval length in which a certain number of jobs of tsk can be spawned. *)
+ Section SeparationBound.
+
+ (* Let min_length denote any function that takes a number of jobs and
+ returns an associated interval length.
+ (This corresponds to the delta function in the literature.) *)
+ Variable min_length: Task > nat > time.
+
+ (* Then, we say that min_length is a separation bound iff, for any number of jobs
+ of tsk, min_separation lowerbounds the minimum interval length in which that number
+ of jobs can be spawned. *)
+ Definition is_separation_bound tsk :=
+ forall t1 t2,
+ t1 <= t2 >
+ min_length tsk (num_arrivals_of_tsk tsk t1 t2) <= t2  t1.
+
+ End SeparationBound.
+
+ End DefiningArrivalCurves.
+
+End ArrivalCurves.
+
diff git a/model/priority.v b/model/priority.v
index 3166c5196ac4ba069d635bbde7a080d6bceb67a3..7360cacb31d6af283507fc430f1093e82dac3044 100644
 a/model/priority.v
+++ b/model/priority.v
@@ 51,8 +51,8 @@ Module Priority.
Section PropertiesFP.
(* Assume that jobs are spawned by tasks. *)
 Context {Job: eqType}.
Context {Task: eqType}.
+ Context {Job: eqType}.
Variable job_task: Job > Task.
(* Let task_priority be any FP policy. *)
@@ 91,10 +91,15 @@ Module Priority.
(* Next, we define properties of a JLFP policy. *)
Section PropertiesJLFP.
 (* Consider any JLFP policy. *)
+ Context {Task: eqType}.
Context {Job: eqType}.
 Variable arr_seq: arrival_sequence Job.
+ Variable job_task: Job > Task.
+ Variable job_arrival: Job > time.
+ (* Consider any arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* Consider any JLFP policy. *)
Variable job_priority: JLFP_policy Job.
(* Now we define the properties. *)
@@ 115,6 +120,25 @@ Module Priority.
arrives_in arr_seq j2 >
job_priority j1 j2  job_priority j2 j1.
+ (* Recall that the jobs are sequential if they are executed
+ in the order they arrived (for more details see file
+ rt.model.schedule.uni.schedule.v).
+
+ An arbitrary JLFP can violate the sequential jobs hypothesis.
+ For example, consider two jobs j1, j2 of the same task such that
+ [job_arrival j1 < job_arrival j2]. It is possible that the policy
+ will assign a higher priority to the second job [i.e., π(j1) < π(j2)].
+ But this situation contradicts to sequential job hypothesis.
+
+ We say that JLFP respects sequential jobs if for any two jobs
+ j1, j2 from the same task the fact that [job_arrival j1 <= job_arrival j2]
+ implies [π(j1) >= π(j2)]. *)
+ Definition JLFP_respects_sequential_jobs :=
+ forall j1 j2,
+ job_task j1 == job_task j2 >
+ job_arrival j1 <= job_arrival j2 >
+ job_priority j1 j2.
+
End PropertiesJLFP.
(* Next, we define properties of a JLDP policy. *)
@@ 156,6 +180,7 @@ Module Priority.
Context {Task: eqType}.
Variable task_period: Task > time.
Variable task_deadline: Task > time.
+ Variable job_arrival: Job > time.
Variable job_task: Job > Task.
(* Ratemonotonic orders tasks by smaller periods. *)
@@ 196,6 +221,19 @@ Module Priority.
by intros y x z; apply leq_trans.
Qed.
+ (* Any FP respects sequential jobs. *)
+ Lemma any_reflexive_FP_respects_sequential_jobs:
+ forall job_priority: FP_policy Task,
+ FP_is_reflexive job_priority >
+ JLFP_respects_sequential_jobs
+ job_task job_arrival (FP_to_JLFP job_task job_priority).
+ Proof.
+ intros HP REFL j1 j2 TSK ARR.
+ move: TSK => /eqP TSK.
+ unfold FP_to_JLFP; rewrite TSK.
+ by apply REFL.
+ Qed.
+
End Properties.
End KnownFPPolicies.
@@ 203,41 +241,73 @@ Module Priority.
(* In this section, we define known JLFP policies. *)
Section KnownJLFPPolicies.
 Context {Job: eqType}.
 Variable job_arrival: Job > time.
 Variable job_deadline: Job > time.

 Variable arr_seq: arrival_sequence Job.

 (* We define earliest deadline first (EDF) as ordering jobs by absolute deadlines. *)
 Definition EDF (j1 j2: Job) :=
 job_arrival j1 + job_deadline j1 <= job_arrival j2 + job_deadline j2.

 Section Properties.
+ (* EDF policy. *)
+ Section EDF.
 (* EDF is reflexive. *)
 Lemma EDF_is_reflexive : JLFP_is_reflexive EDF.
 Proof.
 by intros j; apply leqnn.
 Qed.
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_deadline: Job > time.
+
+ Variable arr_seq: arrival_sequence Job.
+
+ (* We define earliest deadline first (EDF) as ordering jobs by absolute deadlines. *)
+ Definition EDF (j1 j2: Job) :=
+ job_arrival j1 + job_deadline j1 <= job_arrival j2 + job_deadline j2.
+
+ Section Properties.
+
+ (* EDF is reflexive. *)
+ Lemma EDF_is_reflexive : JLFP_is_reflexive EDF.
+ Proof.
+ by intros j; apply leqnn.
+ Qed.
+
+ (* EDF is transitive. *)
+ Lemma EDF_is_transitive : JLFP_is_transitive EDF.
+ Proof.
+ by intros y x z; apply leq_trans.
+ Qed.
+
+ (* EDF is total. *)
+ Lemma EDF_is_total : JLFP_is_total arr_seq EDF.
+ Proof.
+ unfold EDF; intros x y ARRx ARRy.
+ case (leqP (job_arrival x + job_deadline x)
+ (job_arrival y + job_deadline y));
+ [by rewrite orTb  by move/ltnW => >].
+ Qed.
+
+ End Properties.
+
+ End EDF.
+
+ (* EDF in the presence of tasks. *)
+ Section EDFwithTasks.
+
+ Context {Task: eqType}.
+ Variable task_deadline: Task > time.
 (* EDF is transitive. *)
 Lemma EDF_is_transitive : JLFP_is_transitive EDF.
 Proof.
 by intros y x z; apply leq_trans.
 Qed.
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_task: Job > Task.
 (* EDF is total. *)
 Lemma EDF_is_total : JLFP_is_total arr_seq EDF.
+ (* Notice that in the presence of tasks the relative dealine
+ of a job is equal to the relative deadline of its task. *)
+ Definition job_relative_dealine (j: Job) := task_deadline (job_task j).
+
+ (* EDF respects sequential jobs.*)
+ Lemma EDF_respects_sequential_jobs:
+ JLFP_respects_sequential_jobs
+ job_task job_arrival (EDF job_arrival job_relative_dealine).
Proof.
 unfold EDF; intros x y ARRx ARRy.
 case (leqP (job_arrival x + job_deadline x)
 (job_arrival y + job_deadline y));
 [by rewrite orTb  by move/ltnW => >].
+ intros j1 j2 TSK ARR.
+ move: TSK => /eqP TSK.
+ unfold EDF, job_relative_dealine; rewrite TSK.
+ by rewrite leq_add2r.
Qed.

 End Properties.

+
+ End EDFwithTasks.
+
End KnownJLFPPolicies.
(* In this section, we define the notion of a possible interfering task. *)
diff git a/model/schedule/apa/constrained_deadlines.v b/model/schedule/apa/constrained_deadlines.v
index f3d6c7096848ceab8699401ad22c672b5eea8cac..a768a41b429283d66cfb8a9500b43d6595578099 100644
 a/model/schedule/apa/constrained_deadlines.v
+++ b/model/schedule/apa/constrained_deadlines.v
@@ 266,7 +266,7 @@ Module ConstrainedDeadlines.
assert (LEt: job_arrival j' + task_period tsk <= t).
by apply leq_trans with (n := job_arrival j); first by rewrite SAMEtsk.
apply NOTCOMP'.
 apply completion_monotonic with (t0 := job_arrival j' + task_period tsk); [by done  by done ].
+ apply completion_monotonic with (t0 := job_arrival j' + task_period tsk); [by done ].
apply PREVtsk; try (by done).
apply leq_trans with (n := job_arrival j' + task_period tsk); last by rewrite SAMEtsk.
rewrite addn1; apply leq_add; first by done.
diff git a/model/schedule/global/basic/schedule.v b/model/schedule/global/basic/schedule.v
index 973eb780d57710e809a97201e71340e55d210001..f93edba882d5307d0c60c7f36e18758c66a34538 100644
 a/model/schedule/global/basic/schedule.v
+++ b/model/schedule/global/basic/schedule.v
@@ 68,7 +68,7 @@ Module Schedule.
Definition service_during (t1 t2: time) := \sum_(t1 <= t < t2) service_at t.
(* Job j has completed at time t if it received enough service. *)
 Definition completed (t: time) := service t == job_cost j.
+ Definition completed (t: time) := service t >= job_cost j.
(* Job j is pending at time t iff it has arrived but has not completed. *)
Definition pending (t: time) := has_arrived job_arrival j t && ~~completed t.
@@ 277,10 +277,9 @@ Module Schedule.
completed job_cost sched j t >
completed job_cost sched j t'.
Proof.
 unfold completed; move => t t' LE /eqP COMPt.
 rewrite eqn_leq; apply/andP; split; first by apply H_completed_jobs.
 by apply leq_trans with (n := service sched j t);
 [by rewrite COMPt  by apply extend_sum].
+ unfold completed; move => t t' LE COMPt.
+ apply leq_trans with (service sched j t); first by done.
+ by rewrite /service /service_during [in X in _ <= X](@big_cat_nat _ _ _ t) //= leq_addr.
Qed.
(* A completed job cannot be scheduled. *)
@@ 294,10 +293,10 @@ Module Schedule.
intros t COMPLETED.
apply/negP; red; intro SCHED.
have BUG := COMP j t.+1.
 rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
 unfold service; rewrite big_nat_recr // /= addn1.
 apply leq_add; first by move: COMPLETED => /eqP <.
 by rewrite lt0n not_scheduled_no_service negbK.
+ rewrite leqNgt in BUG; move: BUG => /negP BUG; apply: BUG.
+ unfold service, service_during; rewrite big_nat_recr // /= addn1.
+ apply leq_add; first by done.
+ by rewrite lt0n not_scheduled_no_service negbK.
Qed.
(* The service received by job j in any interval is no larger than its cost. *)
@@ 394,8 +393,7 @@ Module Schedule.
have BUG := COMP j t.+1.
rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
unfold service; rewrite addn1 big_nat_recr // /=.
 apply leq_add;
 first by move: COMPLETED => /eqP COMPLETED; rewrite COMPLETED.
+ apply leq_add; first by done.
rewrite lt0n; apply/eqP; red; move => /eqP NOSERV.
rewrite not_scheduled_no_service in NOSERV.
by rewrite SCHED in NOSERV.
diff git a/model/schedule/global/jitter/schedule.v b/model/schedule/global/jitter/schedule.v
index 2a7e37f4c073614a607f7529ceb6bdffd6a304a9..18409931ae8b2ab33f7d1041699341fd9454f84c 100644
 a/model/schedule/global/jitter/schedule.v
+++ b/model/schedule/global/jitter/schedule.v
@@ 86,8 +86,7 @@ Module ScheduleWithJitter.
have BUG := COMP j t.+1.
rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
unfold service; rewrite addn1 big_nat_recr // /=.
 apply leq_add;
 first by move: COMPLETED => /eqP COMPLETED; rewrite COMPLETED.
+ apply leq_add; first by done.
rewrite lt0n; apply/eqP; red; move => /eqP NOSERV.
rewrite not_scheduled_no_service in NOSERV.
by rewrite SCHED in NOSERV.
diff git a/model/schedule/global/response_time.v b/model/schedule/global/response_time.v
index 33f2c6aac65fcc18146b079112bf6f8a5a261d77..865d4996187324a812613ae3214f98ca9afaa01a 100644
 a/model/schedule/global/response_time.v
+++ b/model/schedule/global/response_time.v
@@ 71,14 +71,9 @@ Module ResponseTime.
unfold is_response_time_bound_of_task, completed,
completed_jobs_dont_execute in *.
apply/eqP; rewrite leqn0.
 rewrite < leq_add2l with (p := job_cost j).
 move: RT => /eqP RT; rewrite {1}RT addn0.
 apply leq_trans with (n := service sched j t'.+1);
 last by apply EXEC.
 unfold service; rewrite > big_cat_nat with
 (p := t'.+1) (n := job_arrival j + R);
 [rewrite leq_add2l /=  by ins  by apply ltnW].
 by rewrite big_nat_recr // /=; apply leq_addl.
+ eapply completion_monotonic in RT; eauto 2.
+ apply completed_implies_not_scheduled in RT; eauto 2.
+ by move: RT; rewrite not_scheduled_no_service; move => /eqP RT; rewrite RT.
Qed.
(* The same applies for the cumulative service of job j. *)
diff git a/model/schedule/global/schedulability.v b/model/schedule/global/schedulability.v
index 6bde68577536360c62406e1c718c0e9d580a3b34..14d59ddc8220898227eaf49e8a5e01c34fc524ea 100644
 a/model/schedule/global/schedulability.v
+++ b/model/schedule/global/schedulability.v
@@ 102,17 +102,13 @@ Module Schedulability.
service_at sched j t' = 0.
Proof.
intros t' LE.
 rename no_deadline_miss into NOMISS,
+ rename no_deadline_miss into RT,
H_completed_jobs_dont_execute into EXEC.
unfold job_misses_no_deadline, completed, completed_jobs_dont_execute in *.
apply/eqP; rewrite leqn0.
 rewrite < leq_add2l with (p := job_cost j).
 move: NOMISS => /eqP NOMISS; rewrite {1}NOMISS addn0.
 apply leq_trans with (n := service sched j t'.+1); last by apply EXEC.
 unfold service; rewrite > big_cat_nat with
 (p := t'.+1) (n := job_arrival j + job_deadline j);
 [rewrite leq_add2l /=  by ins  by apply ltnW].
 by rewrite big_nat_recr // /=; apply leq_addl.
+ eapply completion_monotonic in RT; eauto 2.
+ apply completed_implies_not_scheduled in RT; eauto 2.
+ by move: RT; rewrite not_scheduled_no_service; move => /eqP RT; rewrite RT.
Qed.
(* The same applies for the cumulative service of job j. *)
diff git a/model/schedule/partitioned/schedulability.v b/model/schedule/partitioned/schedulability.v
index 42081b6dca83e57ba89b5c01ec581446a92f73db..acb8d25b74f80a081f4f6d0a6d1bd0cca2d8fcc9 100644
 a/model/schedule/partitioned/schedulability.v
+++ b/model/schedule/partitioned/schedulability.v
@@ 121,9 +121,8 @@ Module PartitionSchedulability.
H_partitioned into PART.
intros tsk IN j ARRj JOBtsk.
specialize (SCHED tsk IN j ARRj JOBtsk).
 move: SCHED => /eqP <.
unfold service, uni.service, service_during, uni.service_during in *.
 by apply/eqP; rewrite SAME // JOBtsk.
+ by rewrite SAME // JOBtsk.
Qed.
End Schedulability.
diff git a/model/schedule/uni/basic/busy_interval.v b/model/schedule/uni/basic/busy_interval.v
deleted file mode 100644
index 14b277fe1a8c2ed59031f065fd995cd4d74e8a08..0000000000000000000000000000000000000000
 a/model/schedule/uni/basic/busy_interval.v
+++ /dev/null
@@ 1,715 +0,0 @@
Require Import rt.util.all.
Require Import rt.model.arrival.basic.task rt.model.arrival.basic.job rt.model.arrival.basic.arrival_sequence
 rt.model.priority rt.model.arrival.basic.task_arrival.
Require Import rt.model.schedule.uni.schedule rt.model.schedule.uni.service
 rt.model.schedule.uni.workload.
Require Import rt.model.schedule.uni.basic.platform.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.

Module BusyInterval.

 Import Job UniprocessorSchedule Priority Platform
 Service Workload TaskArrival.

 (* In this section, we define the notion of a busy interval. *)
 Section Defs.

 Context {Task: eqType}.
 Context {Job: eqType}.
 Variable job_arrival: Job > time.
 Variable job_cost: Job > time.
 Variable job_task: Job > Task.

 (* Consider any arrival sequence with consistent arrival times... *)
 Variable arr_seq: arrival_sequence Job.
 Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.

 (* ...and any uniprocessor schedule of these jobs. *)
 Variable sched: schedule Job.
 Hypothesis H_jobs_come_from_arrival_sequence:
 jobs_come_from_arrival_sequence sched arr_seq.

 (* Assume a given JLFP policy. *)
 Variable higher_eq_priority: JLFP_policy Job.

 (* Let j be the job to be analyzed. *)
 Variable j: Job.
 Hypothesis H_from_arrival_sequence: arrives_in arr_seq j.

 (* For simplicity, let's define some local names. *)
 Let job_pending_at := pending job_arrival job_cost sched.
 Let job_scheduled_at := scheduled_at sched.
 Let job_completed_by := completed_by job_cost sched.

 (* We say that t is a quiet time for j iff every higherpriority job from
 the arrival sequence that arrived before t has completed by that time. *)
 Definition quiet_time (t: time) :=
 forall j_hp,
 arrives_in arr_seq j_hp >
 higher_eq_priority j_hp j >
 arrived_before job_arrival j_hp t >
 job_completed_by j_hp t.

 (* Based on the definition of quiet time, we say that interval
 [t1, t_busy) is a (potentially unbounded) busyinterval prefix
 iff the interval starts with a quiet time and remains nonquiet. *)
 Definition busy_interval_prefix (t1 t_busy: time) :=
 t1 < t_busy /\
 quiet_time t1 /\
 (forall t, t1 < t < t_busy > ~ quiet_time t).

 (* Next, we say that an interval [t1, t2) is a busy interval iff
 [t1, t2) is a busyinterval prefix and t2 is a quiet time. *)
 Definition busy_interval (t1 t2: time) :=
 busy_interval_prefix t1 t2 /\
 quiet_time t2.

 (* Now we prove some lemmas about busy intervals. *)
 Section Lemmas.

 (* Recall the list of jobs that arrive in any interval. *)
 Let arrivals_between := jobs_arrived_between arr_seq.

 (* We begin by proving basic lemmas about the arrival and
 completion of jobs that are pending during a busy interval. *)
 Section BasicLemmas.

 (* Assume that the priority relation is reflexive. *)
 Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.

 (* Consider any busy interval [t1, t2)... *)
 Variable t1 t2: time.
 Hypothesis H_busy_interval: busy_interval t1 t2.

 (* ...and assume that job j is pending during this busy interval. *)
 Variable t: time.
 Hypothesis H_during_interval: t1 <= t < t2.
 Hypothesis H_job_is_pending: job_pending_at j t.

 (* First, we prove that job j completes by the end of the busy interval. *)
 Section CompletesDuringBusyInterval.

 Lemma job_completes_within_busy_interval:
 job_completed_by j t2.
 Proof.
 rename H_priority_is_reflexive into REFL, H_busy_interval into BUSY,
 H_during_interval into INT, H_job_is_pending into PEND.
 move: BUSY => [_ QUIET].
 move: INT => /andP [_ LT2].
 apply QUIET; [by done  by apply REFL ].
 apply leq_ltn_trans with (n := t); last by done.
 by move: PEND => /andP [ARR _].
 Qed.

 End CompletesDuringBusyInterval.

 (* Next, we prove that job j cannot have arrived before the
 busy interval. *)
 Section ArrivesDuringBusyInterval.

 (* Assume that jobs do not execute after completion. *)
 Hypothesis H_completed_jobs_dont_execute:
 completed_jobs_dont_execute job_cost sched.

 (* Then, we prove that j arrives no earlier than t1. *)
 Lemma job_arrives_within_busy_interval:
 t1 <= job_arrival j.
 Proof.
 rename H_priority_is_reflexive into REFL, H_busy_interval into BUSY,
 H_during_interval into INT, H_job_is_pending into PEND.
 apply contraT; rewrite ltnNge; intro LT1.
 move: BUSY => [[_ [QUIET _]] _].
 move: PEND => /andP [_ /negP NOTCOMP].
 move: INT => /andP [LE _].
 exfalso; apply NOTCOMP.
 apply completion_monotonic with (t0 := t1); try (by done).
 by apply QUIET; [by done  by apply REFL ].
 Qed.

 End ArrivesDuringBusyInterval.

 End BasicLemmas.

 (* In this section, we prove that during a busy interval there
 always exists a pending job. *)
 Section ExistsPendingJob.

 (* Assume that jobs do not execute after completion. *)
 Hypothesis H_completed_jobs_dont_execute:
 completed_jobs_dont_execute job_cost sched.

 (* Let [t1, t2] be any interval where time t1 is quiet and
 time t2 is not quiet. *)
 Variable t1 t2: time.
 Hypothesis H_interval: t1 <= t2.
 Hypothesis H_quiet: quiet_time t1.
 Hypothesis H_not_quiet: ~ quiet_time t2.

 (* Then, we prove that there exists a job pending at time t2
 that has higher or equal priority (with respect ot tsk). *)
 Lemma not_quiet_implies_exists_pending_job:
 exists j_hp,
 arrives_in arr_seq j_hp /\
 arrived_between job_arrival 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 with (job_arrival0 := job_arrival) 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 workconserving and that jobs do
 not execute before their arrival or after completion. *)
 Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
 Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
 Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.

 (* Consider any interval [t1, t2] such that t1 < t2 and t1 is the only quiet time. *)
 Variable t1 t2: time.
 Hypothesis H_strictly_larger: t1 < t2.
 Hypothesis H_quiet: quiet_time t1.
 Hypothesis H_not_quiet: forall t, t1 < t <= t2 > ~ quiet_time t.

 (* We prove that at every time t in [t1, t2], the processor is not idle. *)
 Lemma not_quiet_implies_not_idle:
 forall t,
 t1 <= t <= t2 >
 ~ is_idle sched t.
 Proof.
 unfold total_service_during, work_conserving in *.
 rename H_not_quiet into NOTQUIET, H_work_conserving into WORK.
 move => t /andP [GEt LEt] /eqP IDLE.
 rewrite leq_eqVlt in GEt; move: GEt => /orP [/eqP EQUAL  LARGER].
 {
 subst t.
 feed (NOTQUIET t1.+1); first by apply/andP; split.
 apply NOTQUIET.
 intros j_hp IN HP ARR.
 apply completion_monotonic with (t := t1); [by done  by done ].
 apply contraT; intro NOTCOMP.
 destruct (scheduled_at sched j_hp t1) eqn:SCHEDhp;
 first by move: SCHEDhp => /eqP SCHEDhp; rewrite IDLE in SCHEDhp.
 apply negbT in SCHEDhp.
 feed (WORK j_hp t1 IN);
 first by rewrite /arrived_before ltnS in ARR; repeat (apply/andP; split).
 move: WORK => [j_other /eqP SCHEDother].
 by rewrite IDLE in SCHEDother.
 }
 {
 feed (NOTQUIET t); first by apply/andP; split.
 apply NOTQUIET; clear NOTQUIET.
 intros j_hp IN HP ARR.
 apply contraT; intros NOTCOMP.
 destruct (scheduled_at sched j_hp t) eqn:SCHEDhp;
 first by move: SCHEDhp => /eqP SCHEDhp; rewrite IDLE in SCHEDhp.
 apply negbT in SCHEDhp.
 feed (WORK j_hp t IN);
 first by repeat (apply/andP; split); first by apply ltnW.
 move: WORK => [j_other /eqP SCHEDother].
 by rewrite IDLE in SCHEDother.
 }
 Qed.

 (* In fact, we can infer a stronger property. *)
 Section OnlyHigherOrEqualPriority.

 (* If the JLFP policy is transitive and is respected by the schedule, ...*)
 Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.
 Hypothesis H_respects_policy:
 respects_JLFP_policy job_arrival job_cost arr_seq sched higher_eq_priority.

 (* ... then the processor is always busy with a job of higher or equal priority. *)
 Lemma not_quiet_implies_exists_scheduled_hp_job:
 forall t,
 t1 <= t < t2 >
 exists j_hp,
 arrived_between job_arrival j_hp t1 t2 /\
 higher_eq_priority j_hp j /\
 job_scheduled_at j_hp t.
 Proof.
 have NOTIDLE := not_quiet_implies_not_idle.
 unfold is_idle, FP_is_transitive, transitive in *.
 rename H_not_quiet into NOTQUIET, H_quiet into QUIET, H_priority_is_transitive into TRANS,
 H_work_conserving into WORK, H_respects_policy into PRIO,
 H_jobs_come_from_arrival_sequence into CONS.
 move => t /andP [GEt LEt].
 feed (NOTIDLE t); first by apply/andP; split; last by apply ltnW.
 destruct (sched t) as [j_hp] eqn:SCHED; [clear NOTIDLE  by exfalso; apply NOTIDLE].
 move: SCHED => /eqP SCHED.
 exists j_hp.
 have HP: higher_eq_priority j_hp j.
 {
 apply contraT; move => /negP NOTHP; exfalso.
 feed (NOTQUIET t.+1); first by apply/andP; split.
 apply NOTQUIET.
 unfold quiet_time in *; intros j_hp' IN HP ARR.
 apply contraT; move => /negP NOTCOMP'; exfalso.
 have BACK: backlogged job_arrival job_cost sched j_hp' t.
 {
 apply/andP; split; last first.
 {
 apply/negP; intro SCHED'.
 apply only_one_job_scheduled with (j1 := j_hp) in SCHED'; last by done.
 by subst; rewrite HP in NOTHP.
 }
 apply/andP; split; first by done.
 apply/negP; intro COMP; apply NOTCOMP'.
 by apply completion_monotonic with (t0 := t).
 }
 feed (PRIO j_hp' j_hp t IN BACK); first by done.
 by apply NOTHP, TRANS with (y := j_hp').
 }
 repeat split; [ by done  by done].
 {
 move: (SCHED) => PENDING.
 eapply scheduled_implies_pending with (job_cost0 := job_cost) in PENDING;
 [ by eauto  by done].
 apply/andP; split;
 last by apply leq_ltn_trans with (n := t); first by move: PENDING => /andP [ARR _].
 apply contraT; rewrite ltnNge; intro LT; exfalso.
 feed (QUIET j_hp); first by eapply CONS, SCHED.
 specialize (QUIET HP LT).
 have COMP: job_completed_by j_hp t by apply completion_monotonic with (t0 := t1).
 apply completed_implies_not_scheduled in COMP; last by done.
 by move: COMP => /negP COMP; apply COMP.
 }
 Qed.

 End OnlyHigherOrEqualPriority.

 End ProcessorAlwaysBusy.

 (* 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 there are no duplicate job arrivals... *)
 Hypothesis H_arrival_sequence_is_a_set:
 arrival_sequence_is_a_set arr_seq.

 (* ...and that jobs do not execute before their arrival or after completion. *)
 Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
 Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.

 (* Also assume a workconserving FP schedule, ... *)
 Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
 Hypothesis H_respects_policy:
 respects_JLFP_policy job_arrival job_cost arr_seq sched higher_eq_priority.

 (* ...in which the priority relation is reflexive and transitive. *)
 Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.
 Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.

 (* Next, we recall the notion of workload of all jobs released in a given interval
 [t1, t2) that have higherorequal priority than the job j being analyzed. *)
 Let hp_workload t1 t2 :=
 workload_of_higher_or_equal_priority_jobs job_cost (arrivals_between t1 t2)
 higher_eq_priority j.

 (* With regard to the jobs with higherorequal 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 (arrivals_between t1 t2)
 higher_eq_priority 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: time.
 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 exists a (potentially unbounded)
 busy interval that starts prior to 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_respects_policy into PRIO,
 H_work_conserving into WORK, H_priority_is_reflexive into REFL,
 H_from_arrival_sequence into FROM.
 unfold busy_interval_prefix.
 set dec_quiet :=
 fun t => all (fun j_hp =>
 higher_eq_priority j_hp j ==> (completed_by job_cost sched j_hp t))
 (jobs_arrived_before arr_seq t).
 destruct ([exists t:'I_t_busy.+1, dec_quiet t]) eqn:EX.
 {
 set last := \max_(t < t_busy.+1  dec_quiet t) t.
 move: EX => /existsP [t EX].
 have PRED: dec_quiet last by apply (bigmax_pred t_busy.+1 dec_quiet t).
 have QUIET: quiet_time last.
 {
 move: PRED => /allP PRED.
 intros j_hp IN HP ARR.
 feed (PRED j_hp).
 by apply arrived_between_implies_in_arrivals with (job_arrival0 := job_arrival).
 by rewrite HP implyTb in PRED.
 }
 exists last.
 split; last first.
 {
 apply/andP; split; last by move: PEND => /andP [ARR _].
 apply contraT; rewrite ltnNge; intros BEFORE.
 feed (QUIET j FROM); first by apply REFL.
 specialize (QUIET BEFORE).
 move: PEND => /andP [_ NOTCOMP].
 apply completion_monotonic with (t' := t_busy) in QUIET;
 [by rewrite QUIET in NOTCOMP  by done ].
 by apply bigmax_ltn_ord with (i0 := t).
 }
 split; first by apply bigmax_ltn_ord with (i0 := t).
 split; first by done.
 {
 move => t0 /andP [GTlast LTbusy] QUIET0.
 have PRED0: dec_quiet t0.
 {
 apply/allP; intros j_hp ARR; apply/implyP; intros HP.
 apply QUIET0; [ by done ].
  by eapply in_arrivals_implies_arrived; eauto.
  by eapply in_arrivals_implies_arrived_before; eauto.
 }
 have BUG: t0 <= last.
 {
 have LE := @leq_bigmax_cond _ (fun (x: 'I_t_busy.+1) => dec_quiet x)
 (fun x => x) (Ordinal LTbusy) PRED0.
 by apply LE.
 }
 apply leq_trans with (p := last) in GTlast; last by done.
 by rewrite ltnn in GTlast.
 }
 }
 {
 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 _].
 split; first by done.
 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; [ by done ].
  by eapply in_arrivals_implies_arrived; eauto.
  by eapply in_arrivals_implies_arrived_before; eauto.
 }
 Qed.

 End LowerBound.

 (* Next we prove that, if there is a point where the requested workload
 is upperbounded by the supply, then the busy interval eventually ends. *)
 Section UpperBound.

 (* Consider any busy interval that starts at time t1 <= job_arrival j. *)
 Variable t1: time.
 Hypothesis H_is_busy_prefix: busy_interval_prefix t1 t_busy.+1.
 Hypothesis H_busy_prefix_contains_arrival: job_arrival j >= t1.

 (* Next, assume that for some delta > 0, the requested workload
 at time (t1 + delta) is bounded by delta (i.e., the supply). *)
 Variable delta: time.
 Hypothesis H_delta_positive: delta > 0.
 Hypothesis H_workload_is_bounded: hp_workload t1 (t1 + delta) <= delta.

 (* If there exists 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 nonquiet, the processor is always busy
 with tasks of higherorequal priority. *)
 Lemma busy_interval_has_uninterrupted_service:
 hp_service t1 (t1 + delta) = delta.
 Proof.
 rename H_is_busy_prefix into PREFIX.
 have EXISTS := not_quiet_implies_exists_scheduled_hp_job.
 feed_n 3 EXISTS; try (by done).
 apply eq_trans with (y := \sum_(t1 <= t < t1 + delta) 1);
 last by simpl_sum_const; rewrite addKn.
 unfold hp_service, service_of_higher_or_equal_priority_jobs, service_of_jobs.
 rewrite exchange_big /=.
 apply eq_big_nat; move => t /andP [GEt LTt].
 move: PREFIX => [_ [QUIET _]].
 have EX: exists j_hp,
 arrived_between job_arrival j_hp t1 (t1 + delta) /\
 higher_eq_priority j_hp j /\
 scheduled_at sched j_hp t.
 {
 apply EXISTS with (t1 := t1) (t2 := t1 + delta); try (by done);
 last by apply/andP; split.
 by rewrite addn1; apply leq_add.
 } clear EXISTS.
 move: EX => [j_hp [/andP [GE LT] [HP SCHED]]].
 have ARRhp: arrives_in arr_seq j_hp.
 by apply (H_jobs_come_from_arrival_sequence j_hp t).
 rewrite big_mkcond (bigD1_seq j_hp) /=; first last.
  by eapply arrivals_uniq; eauto 1.
  by eapply arrived_between_implies_in_arrivals; eauto 1; apply/andP; split.
 rewrite HP big1; first by rewrite /service_at SCHED addn0.
 intros j' NEQ; destruct (higher_eq_priority j' j); last by done.
 apply/eqP; rewrite eqb0; apply/negP; move => SCHED'.
 move: NEQ => /eqP NEQ; apply NEQ.
 by apply only_one_job_scheduled with (sched0 := sched) (t0 := t).
 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
 H_completed_jobs_dont_execute.
 rename H_no_quiet_time into NOTQUIET,
 H_is_busy_prefix into PREFIX, H_respects_policy into PRIO.
 set l := jobs_arrived_between arr_seq 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));
 first by apply/andP; split;
 first by rewrite addn1; apply leq_add.
 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_(_ < _  hep _ _)_]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.
 }
 rewrite ltn_neqAle; apply/andP; split; last by apply cumulative_service_le_job_cost.
 unfold service_during.
 rewrite (ignore_service_before_arrival job_arrival); rewrite //; [ by apply ltnW].
 rewrite < ignore_service_before_arrival with (t2:=0); rewrite //; [by apply ltnW].
 by 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:
 hp_workload t1 (t1 + delta) > delta.
 Proof.
 rewrite {1}busy_interval_has_uninterrupted_service.
 by 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.
 have TOOMUCH := busy_interval_workload_larger_than_interval.
 have BOUNDED := H_workload_is_bounded.
 rename H_is_busy_prefix into PREFIX.

 set dec_quiet :=
 fun t =>
 all (fun j_hp => higher_eq_priority j_hp j ==> (completed_by job_cost sched j_hp t))
 (jobs_arrived_before arr_seq t).

 destruct ([exists t2:'I_(t1 + delta).+1, (t2 > t1) && dec_quiet t2]) eqn:EX.
 {
 have EX': exists (t2: nat), ((t1 < t2 <= t1 + delta) && dec_quiet t2).
 {
 move: EX => /existsP [t2 /andP [LE QUIET]].
 exists t2; apply/andP; split; last by done.
 by apply/andP; split; last by rewrite ltnS; apply ltn_ord.
 }
 have MIN := ex_minnP EX'.
 move: MIN => [t2 /andP [/andP [GT LE] QUIET] MIN]; clear EX EX'.
 exists t2; split; first by done.
 split; last first.
 {
 intros j_hp IN HP ARR.
 move: QUIET => /allP QUIET.
 feed (QUIET j_hp);
 first by eapply arrived_between_implies_in_arrivals; last by apply ARR.
 by move: QUIET => /implyP QUIET; apply QUIET.
 }
 split; first by done.
 split; first by move: PREFIX => [_ [QUIET1 _]].
 move => t /andP [GT1 LT2] BUG.
 feed (MIN t).
 {
 apply/andP; split;
 first by apply/andP; split;
 last by apply leq_trans with (n := t2); [by apply ltnW ].
 apply/allP; intros j_hp ARR; apply/implyP; intro HP.
 apply BUG; [ by done ].
  by eapply in_arrivals_implies_arrived, ARR.
  by eapply in_arrivals_implies_arrived_before, ARR.
 }
 by apply leq_ltn_trans with (p := t2) in MIN; first by rewrite ltnn in MIN.
 }
 {
 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; [ by done ].
  by eapply in_arrivals_implies_arrived, ARR.
  by eapply in_arrivals_implies_arrived_before, ARR.
 } exfalso; clear ALL'.
 specialize (TOOMUCH ALL).
 by have BUG := leq_trans TOOMUCH BOUNDED; rewrite ltnn in BUG.
 }
 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.

 (* Assume that for some delta > 0, the requested workload at
 time (t1 + delta) is bounded by delta (i.e., the supply). *)
 Variable delta: time.
 Hypothesis H_delta_positive: delta > 0.
 Hypothesis H_workload_is_bounded:
 forall t, hp_workload t (t + delta) <= delta.

 (* By assuming that job j has positive cost, we can infer that
 there always 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.
 rename H_workload_is_bounded into WORK.
 feed (PREFIX (job_arrival j)).
 {
 apply/andP; split; first by apply leqnn.
 rewrite /completed_by /service /service_during.
 rewrite (ignore_service_before_arrival job_arrival) //.
 rewrite big_geq; last by apply leqnn.
 by rewrite eq_sym lt0n H_positive_cost.
 }
 move: PREFIX => [t1 [PREFIX /andP [GE1 GEarr]]].
 have BOUNDED := busy_interval_is_bounded (job_arrival j) t1 PREFIX delta.
 feed_n 2 BOUNDED; [by done  by apply WORK  ].
 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 responsetime bound. *)
 Section ResponseTimeBoundFromBusyInterval.

 (* Assume that for some delta > 0, the requested workload
 at time (t1 + delta) is bounded by delta (i.e., the supply). *)
 Variable delta: time.
 Hypothesis H_delta_positive: delta > 0.
 Hypothesis H_workload_is_bounded:
 forall t,
 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 delta.
 destruct (job_cost j == 0) eqn:COST.
 {
 move: COST => /eqP COST.
 rewrite /job_completed_by /completed_by eqn_leq.
 apply/andP; split;
 first by apply cumulative_service_le_job_cost.
 by rewrite COST.
 }
 apply negbT in COST; rewrite lt0n in COST.
 feed_n 3 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) (t := job_arrival j);
 try (by done); first by apply/andP; split.
 apply/andP; split; first by apply leqnn.
 rewrite /completed_by /service /service_during.
 rewrite (ignore_service_before_arrival job_arrival) //.
 rewrite big_geq; last by apply leqnn.
 by rewrite eq_sym lt0n.
 Qed.

 End ResponseTimeBoundFromBusyInterval.

 End BoundingBusyInterval.

 End Lemmas.

 End Defs.

End BusyInterval.
\ No newline at end of file
diff git a/model/schedule/uni/basic/platform.v b/model/schedule/uni/basic/platform.v
index 74c0c36325f3ac8801be454d8b6f72f8bb1cc2b7..aaf70c03f7bfed65d6ac05f764089ccf13554bd3 100644
 a/model/schedule/uni/basic/platform.v
+++ b/model/schedule/uni/basic/platform.v
@@ 153,8 +153,6 @@ Module Platform.
rewrite /job_completed_by /completed_by /service /service_during.
rewrite (ignore_service_before_arrival job_arrival);
[  by done  by done  by apply leq_addr].
 rewrite eqn_leq; apply/andP; split;
 first by apply cumulative_service_le_job_cost.
apply leq_trans with (n := \sum_(job_arrival j <= t < job_arrival j + job_cost j) 1);
first by simpl_sum_const; rewrite addKn leqnn.
apply leq_trans with (n := \sum_(job_arrival j <= t < job_arrival j + job_cost j)
@@ 170,7 +168,7 @@ Module Platform.
}
apply BACK; apply/andP; split; last by done.
apply/andP; split; first by done.
 rewrite neq_ltn; apply/orP; left.
+ rewrite ltnNge.
rewrite /service /service_during.
rewrite > big_cat_nat with (n := job_arrival j);
[simpl  by done  by done].
diff git a/model/schedule/uni/end_time.v b/model/schedule/uni/end_time.v
index c5820ded7fe0485ad9042b4c65e3154de6d62a34..268a45ab8c5ee2aa678acc7aa89229cdec24a886 100644
 a/model/schedule/uni/end_time.v
+++ b/model/schedule/uni/end_time.v
@@ 239,8 +239,8 @@ Module end_time.
intro job_cmplted.
unfold job_completed_by, completed_by, service, service_during.
rewrite (ignore_service_before_arrival job_arrival sched ) //.
  apply service_eq_cost_at_end_time in job_cmplted.
 by apply /eqP.
+  apply service_eq_cost_at_end_time in job_cmplted.
+ by rewrite job_cmplted.
 by apply arrival_le_end in job_cmplted.
Qed.
diff git a/model/schedule/uni/jitter/busy_interval.v b/model/schedule/uni/jitter/busy_interval.v
index 5cb8548d8ad3b05cf5206fb006fda8a326316468..78da89d908940844c1ac8ef4d687a73cdc0b499e 100644
 a/model/schedule/uni/jitter/busy_interval.v
+++ b/model/schedule/uni/jitter/busy_interval.v
@@ 215,7 +215,7 @@ Module BusyInterval.
feed (NOTQUIET t1.+1); first by apply/andP; split.
apply NOTQUIET.
intros j_hp IN HP ARR.
 apply completion_monotonic with (t := t1); [by done  by done ].
+ apply completion_monotonic with (t := t1); [by done ].
apply contraT; intro NOTCOMP.
destruct (scheduled_at sched j_hp t1) eqn:SCHEDhp;
first by move: SCHEDhp => /eqP SCHEDhp; rewrite IDLE in SCHEDhp.
@@ 393,7 +393,7 @@ Module BusyInterval.
specialize (QUIET BEFORE).
move: PEND => /andP [_ NOTCOMP].
apply completion_monotonic with (t' := t_busy) in QUIET;
 [by rewrite QUIET in NOTCOMP  by done ].
+ first by rewrite QUIET in NOTCOMP.
by apply bigmax_ltn_ord with (i0 := t).
}
split; first by apply bigmax_ltn_ord with (i0 := t).
@@ 505,8 +505,7 @@ Module BusyInterval.
Lemma busy_interval_too_much_workload:
actual_hp_workload t1 (t1 + delta) > actual_hp_service t1 (t1 + delta).
Proof.
 have PEND := not_quiet_implies_exists_pending_job
 H_completed_jobs_dont_execute.
+ have PEND := not_quiet_implies_exists_pending_job.
rename H_no_quiet_time into NOTQUIET,
H_is_busy_prefix into PREFIX, H_respects_policy into PRIO.
set l := actual_arrivals_between job_arrival job_jitter arr_seq t1 (t1 + delta).
@@ 536,12 +535,12 @@ Module BusyInterval.
destruct (higher_eq_priority j1 j); last by done.
by apply cumulative_service_le_job_cost.
}
 rewrite ltn_neqAle; apply/andP; split; last by apply cumulative_service_le_job_cost.
+
unfold service_during.
rewrite (ignore_service_before_jitter job_arrival job_jitter) //;
last by apply/andP; split; last by apply ltnW.
rewrite < ignore_service_before_jitter with (t2:=0); rewrite //; [by apply ltnW].
 by apply/negP.
+ by rewrite ltnNge; apply/negP.
Qed.
(* Using the two lemmas above, we infer that the workload is larger than the
@@ 657,19 +656,18 @@ Module BusyInterval.
apply/andP; split; first by apply leqnn.
rewrite /completed_by /service /service_during.
rewrite (cumulative_service_before_jitter_is_zero job_arrival job_jitter) //.
 by rewrite eq_sym lt0n H_positive_cost.
+ by rewrite ltnNge.
}
move: PREFIX => [t1 [PREFIX /andP [GE1 GEarr]]].
have BOUNDED := busy_interval_is_bounded (actual_job_arrival j) t1 PREFIX delta.
feed_n 2 BOUNDED; [by done  by apply WORK  ].
move: BOUNDED => [t2 [GE2 BUSY]].
exists t1, t2; split.
 {
 apply/andP; split; first by done.
+ { 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 exfalso; apply NOTQUIET.
}
by split.
Qed.
@@ 693,15 +691,8 @@ Module BusyInterval.
job_completed_by j (actual_job_arrival j + delta).
Proof.
have BUSY := exists_busy_interval delta.
 destruct (job_cost j == 0) eqn:COST.
 {
 move: COST => /eqP COST.
 rewrite /job_completed_by /completed_by eqn_leq.
 apply/andP; split;
 first by apply cumulative_service_le_job_cost.
 by rewrite COST.
 }
 apply negbT in COST; rewrite lt0n in COST.
+ move: (posnP (job_cost j)) => [ZPOS].
+ { by rewrite /job_completed_by /completed_by Z. }
feed_n 3 BUSY; try (by done).
move: BUSY => [t1 [t2 [/andP [GE1 LT2] [GE2 BUSY]]]].
apply completion_monotonic with (t := t2); try (by done);
@@ 711,7 +702,7 @@ Module BusyInterval.
apply/andP; split; first by apply leqnn.
rewrite /completed_by /service /service_during.
rewrite (cumulative_service_before_jitter_is_zero job_arrival job_jitter) //.
 by rewrite eq_sym lt0n.
+ by rewrite ltnNge.
Qed.
End ResponseTimeBoundFromBusyInterval.
diff git a/model/schedule/uni/jitter/schedule.v b/model/schedule/uni/jitter/schedule.v
index c8b01a3ae88458bdd317c60e860645dc15a78c1c..cfafef9567c4efa285b34594de011afb8021f97e 100644
 a/model/schedule/uni/jitter/schedule.v
+++ b/model/schedule/uni/jitter/schedule.v
@@ 157,9 +157,7 @@ Module UniprocessorScheduleWithJitter.
have BUG := COMP j t.+1.
rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
unfold service, service_during; rewrite addn1 big_nat_recr // /=.
 apply leq_add;
 first by move: COMPLETED => /eqP COMPLETED; rewrite COMPLETED.
 by rewrite /service_at SCHED.
+ by apply leq_add; last rewrite /service_at SCHED.
Qed.
End Pending.
diff git a/model/schedule/uni/limited/abstract_RTA/abstract_rta.v b/model/schedule/uni/limited/abstract_RTA/abstract_rta.v
new file mode 100644
index 0000000000000000000000000000000000000000..621e1306b6ea4c498b76bbe4107a7fd79565c1b8
 /dev/null
+++ b/model/schedule/uni/limited/abstract_RTA/abstract_rta.v
@@ 0,0 +1,457 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time.
+Require Import rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.abstract_RTA.definitions
+ rt.model.schedule.uni.limited.abstract_RTA.sufficient_condition_for_lock_in_service
+ rt.model.schedule.uni.limited.abstract_RTA.reduction_of_search_space.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Abstract ResponseTime Analysis *)
+(** In this module, we propose the general framework for responsetime analysis (RTA)
+ of uniprocessor scheduling of realtime tasks with arbitrary arrival models. *)
+Module AbstractRTA.
+
+ Import Job Epsilon UniprocessorSchedule Service ResponseTime
+ AbstractRTADefinitions AbstractRTALockInService AbstractRTAReduction.
+
+ (* In this section we prove that the maximum among the solutions of the responsetime bound
+ recurrence is a response time bound for tsk. Note that in this section we do not rely on
+ any hypotheses about job sequentiality. *)
+ Section Abstract_RTA.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals... *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Assume that the job costs are no larger than the task costs. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Consider a task set ts... *)
+ Variable ts: list Task.
+
+ (* ... and a task tsk of ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Consider proper job lockin service and task lockin service functions, i.e... *)
+ Variable job_lock_in_service: Job > time.
+ Variable task_lock_in_service: Task > time.
+
+ (* ...we assume that for all jobs in the arrival sequence the lockin service is
+ (1) positive, (2) no bigger than the costs of the corresponding jobs, and
+ (3) a job becomes nonpreemptive after it reaches its lockin service... *)
+ Hypothesis H_proper_job_lock_in_service:
+ proper_job_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* ...and that [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any
+ job of task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Hypothesis H_proper_task_lock_in_service:
+ proper_task_lock_in_service
+ task_cost job_task arr_seq job_lock_in_service task_lock_in_service tsk.
+
+ (* Let's define some local names for clarity. *)
+ Let work_conserving := work_conserving job_arrival job_cost job_task arr_seq sched tsk.
+ Let busy_intervals_are_bounded_by := busy_intervals_are_bounded_by job_arrival job_cost job_task arr_seq sched tsk.
+ Let job_interference_is_bounded_by := job_interference_is_bounded_by job_arrival job_cost job_task arr_seq sched tsk.
+
+ (* Assume we are provided with abstract functions for interference and interfering workload. *)
+ Variable interference: Job > time > bool.
+ Variable interfering_workload: Job > time > time.
+
+ (* We assume that the scheduler is workconserving. *)
+ Hypothesis H_work_conserving: work_conserving interference interfering_workload.
+
+ (* For simplicity, let's define some local names. *)
+ Let cumul_interference := cumul_interference interference.
+ Let cumul_interfering_workload := cumul_interfering_workload interfering_workload.
+ Let busy_interval := busy_interval job_arrival job_cost sched interference interfering_workload.
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+
+ (* Let L be a constant which bounds any busy interval of task tsk. *)
+ Variable L: time.
+ Hypothesis H_busy_interval_exists: busy_intervals_are_bounded_by interference interfering_workload L.
+
+ (* Next, assume that interference_bound_function is a bound on
+ the interference incurred by jobs of task tsk. *)
+ Variable interference_bound_function: Task > time > time > time.
+ Hypothesis H_job_interference_is_bounded:
+ job_interference_is_bounded_by interference interfering_workload interference_bound_function.
+
+ (* For simplicity, let's define a local name for the search space. *)
+ Let is_in_search_space A := is_in_search_space tsk L interference_bound_function A.
+
+ (* Consider any value R that upperbounds the solution of each responsetime recurrence,
+ i.e., for any relative arrival time A in the search space, there exists a corresponding
+ solution F such that F + (task_cost tsk  task_lock_in_service tsk) <= R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = task_lock_in_service tsk + interference_bound_function tsk A (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+ (* In this section we show a detailed proof of the main theorem
+ that establishes that R is a responsetime bound of task tsk. *)
+ Section ProofOfTheorem.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Assume we have a busy interval [t1, t2) of job j that is bounded by L. *)
+ Variable t1 t2: time.
+ Hypothesis H_busy_interval: busy_interval j t1 t2.
+
+ (* Let's define A as a relative arrival time of job j (with respect to time t1). *)
+ Let A := job_arrival j  t1.
+
+ (* In order to prove that R is a responsetime bound of job j, we use hypothesis H_R_is_maximum.
+ Note that the relative arrival time (A) is not necessarily from the search space. However,
+ earlier we have proven that for any A there exists another A_sp from the search space that
+ shares the same IBF value. Moreover, we've also shown that there exists an F_sp such that
+ F_sp is a solution of the response time recurrence for parameter A_sp. Thus, despite the
+ fact that the relative arrival time may not lie in the search space, we can still use
+ the assumption H_R_is_maximum. *)
+
+ (* More formally, consider any A_sp and F_sp such that:.. *)
+ Variable A_sp F_sp: time.
+ (* (a) A_sp is less than or equal to A... *)
+ Hypothesis H_A_gt_Asp: A_sp <= A.
+ (* (b) interference_bound_function(A, x) is equal to interference_bound_function(A_sp, x) for all x less than L... *)
+ Hypothesis H_equivalent:
+ are_equivalent_at_values_less_than (interference_bound_function tsk A) (interference_bound_function tsk A_sp) L.
+ (* (c) A_sp is in the search space, ... *)
+ Hypothesis H_Asp_is_in_search_space: is_in_search_space A_sp.
+ (* (d) A_sp + F_sp is a solution of the response time reccurence... *)
+ Hypothesis H_fixpoint:
+ A_sp + F_sp = task_lock_in_service tsk + interference_bound_function tsk A_sp (A_sp + F_sp).
+ (* (e) and finally, F_sp + (task_last  ε) is no greater than R. *)
+ Hypothesis H_R_gt_Fsp: F_sp + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+ (* In this section, we consider the case where the solution is so large that the value of [t1 + A_sp + F_sp] goes
+ beyond the busy interval. Although this case may be impossible in some scenarios, it can be easily proven,
+ since any job that completes by the end of the busy interval remains completed. *)
+ Section FixpointOutsideBusyInterval.
+
+ (* By assumption, suppose that t2 is less than or equal to [t1 + A_sp + F_sp]. *)
+ Hypothesis H_big_fixpoint_solution: t2 <= t1 + (A_sp + F_sp).
+
+ (* Then we prove that (job_arrival j + R) is no less than t2. *)
+ Lemma t2_le_arrival_plus_R:
+ t2 <= job_arrival j + R.
+ Proof.
+ move: H_busy_interval => [[/andP [GT LT] [QT1 NTQ]] QT2].
+ apply leq_trans with (t1 + (A_sp + F_sp)); first by done.
+ apply leq_trans with (t1 + A + F_sp).
+ { by rewrite !addnA leq_add2r leq_add2l. }
+ rewrite /A subnKC; last by done.
+ rewrite leq_add2l.
+ apply leq_trans with (F_sp + (task_cost tsk  task_lock_in_service tsk)); last by done.
+ by rewrite leq_addr.
+ Qed.
+
+ (* But since we know that the job is completed by the end of its busy interval,
+ we can show that job j is completed by (job arrival j + R) *)
+ Lemma job_completed_by_arrival_plus_R_1:
+ completed_by job_cost sched j (job_arrival j + R).
+ Proof.
+ move: H_busy_interval => [[/andP [GT LT] [QT1 NTQ]] QT2].
+ apply completion_monotonic with t2; try done.
+ apply t2_le_arrival_plus_R.
+ eapply job_completes_within_busy_interval; eauto 2.
+ Qed.
+
+ End FixpointOutsideBusyInterval.
+
+ (* In this section, we consider the complementary case where [t1 + A_sp + F_sp] lies inside the busy interval. *)
+ Section FixpointInsideBusyInterval.
+
+ (* So, assume that [t1 + A_sp + F_sp] is less than t2. *)
+ Hypothesis H_small_fixpoint_solution: t1 + (A_sp + F_sp) < t2.
+
+ (* Next, let's consider two other cases: *)
+ (* CASE 1: the value of the fixpoint is no less than the relative arrival time of job j. *)
+ Section FixpointIsNoLessThanArrival.
+
+ (* Suppose that [A_sp + F_sp] is no less than relative arrival of job j. *)
+ Hypothesis H_fixpoint_is_no_less_than_relative_arrival_of_j: A <= A_sp + F_sp.
+
+ (* Using lemma "solution_for_A_exists" we can find a solution for response time recurrence for A. *)
+ Lemma solution_for_A_exists':
+ exists F,
+ A_sp + F_sp = A + F /\
+ F <= F_sp /\
+ A + F = task_lock_in_service tsk + interference_bound_function tsk A (A + F).
+ Proof.
+ move: (solution_for_A_exists
+ tsk L (fun tsk A R => task_lock_in_service tsk + interference_bound_function tsk A R) A_sp F_sp) => Lemma1.
+ feed_n 2 Lemma1; try done.
+ { move: (H_busy_interval_exists j H_j_arrives H_job_of_tsk H_job_cost_positive) => [t1' [t2' [_ [BOUND BUSY]]]].
+ have EQ:= busy_interval_is_unique _ _ _ _ _ _ _ _ _ _ H_busy_interval BUSY. destruct EQ as [EQ1 EQ2].
+ subst t1' t2'; clear BUSY.
+ by rewrite (ltn_add2l t1); apply leq_trans with t2. }
+ specialize (Lemma1 A).
+ feed_n 2 Lemma1; try done.
+  by apply/andP; split.
+  by intros x H; apply/eqP; rewrite eqn_add2l H_equivalent.
+ Qed.
+
+ (* To prove this lemma, we introduce two temporal notions of the last nonpreemptive region of job j
+ and an execution optimism. We use these notions only inside this proof, so we don't define them
+ explicitly. Let the last nonpreemptive region of job j (last) be the difference between the cost
+ of the job and the j's lockin service (i.e. [job_cost j  job_lock_in_service j]). We know that
+ after j has reached its lockin service, it will additionally be executed [last] units of time.
+ And let execution optimism (optimism) be the difference between the tsk's lockin service
+ and the j's lockin service (i.e. [task_lock_in_service  job_lock_in_service]). And optimism is
+ how much earlier job j has received its lockin service than it could at worst. From lemma
+ j_receives_at_least_lock_in_service we know that service of j by time [t1 + (A + F)  optimism]
+ is no less than [lock_in_service j]. Hence, job j is completed by time [t1 + (A + F)  optimism + last]
+ which is smaller than [job_arrival j + R]. *)
+ Lemma job_completed_by_arrival_plus_R_2:
+ completed_by job_cost sched j (job_arrival j + R).
+ Proof.
+ move: H_proper_job_lock_in_service => [PRJ1 [PRJ2 PRJ3]].
+ move: H_proper_task_lock_in_service => [PRT1 PRT2].
+ have AUTO1: forall m n, n <= n + m; first by intros; rewrite leq_addr.
+ set (job_cost j  job_lock_in_service j) as job_last.
+ set (task_lock_in_service tsk  job_lock_in_service j) as optimism.
+ move: (H_busy_interval) => [[NEQ [QT1 NTQ]] QT2].
+ move: (NEQ) => /andP [GT LT].
+ move: solution_for_A_exists' => [F [EQSUM [F2LEF1 FIX2]]].
+ apply/negP; intros CONTRc.
+ have Fact1: A <= interference_bound_function tsk A (A + F).
+ { apply leq_trans with
+ (AbstractRTADefinitions.cumul_interference interference j t1 (t1 + (A+F))).
+ { unfold AbstractRTADefinitions.cumul_interference.
+ apply leq_trans with
+ (\sum_(t1 <= t < t1 + A) interference j t); last first.
+ { rewrite [in X in _ <= X](@big_cat_nat _ _ _ (t1 + A)) //=; last by rewrite addnA. }
+ { rewrite {1}[A](sum_of_ones t1).
+ rewrite [in X in X <= _]big_nat_cond [in X in _ <= X]big_nat_cond.
+ rewrite leq_sum //.
+ move => t /andP [/andP [NEQ1 NEQ2] _].
+ rewrite lt0b.
+ unfold work_conserving in H_work_conserving.
+ move: (H_work_conserving j t1 t2 t) => CONS.
+ feed_n 5 CONS; try done.
+ { apply/andP; split; first by done.
+ apply leq_trans with (t1 + A); first by done.
+ by rewrite /A subnKC // ltnW.
+ }
+ move: CONS => [CONS1 _].
+ apply/negP; intros CONTR.
+ move: (CONS1 CONTR) => SCHED; clear CONS1 CONTR.
+ apply H_jobs_must_arrive_to_execute in SCHED.
+ move: NEQ2; rewrite ltnNge; move => /negP NEQ2; apply: NEQ2.
+ by rewrite subnKC. }
+ }
+ { apply H_job_interference_is_bounded with t2; try done.
+  by rewrite EQSUM.
+  apply/negP; intros CONTR; apply: CONTRc.
+ apply completion_monotonic with (t1 + (A + F)); try done.
+ rewrite !addnA subnKC // leq_add2l.
+ apply leq_trans with F_sp; first by done.
+ by apply leq_trans with (F_sp + (task_cost tsk  task_lock_in_service tsk)).
+ }
+ }
+ have FleTLIN: task_lock_in_service tsk <= F.
+ { have Fact: forall a b c d, a + b = c + d > b <= d > a >= c.
+ { clear; intros ? ? ? ? EQ NEQ.
+ have Fact: exists k, d = b + k.
+ { by exists (d  b); rewrite subnKC. }
+ move: Fact => [k EQk].
+ subst d; clear NEQ.
+ move: EQ; rewrite [b+k]addnC addnA; move => /eqP; rewrite eqn_add2r; move => /eqP EQ.
+ by subst a; rewrite leq_addr.
+ }
+ by rewrite {1}addnC in FIX2; apply Fact in FIX2.
+ }
+ have NotTooOptimistic: optimism <= F.
+ { apply leq_trans with (task_lock_in_service tsk); last by done.
+ by rewrite /optimism leq_subr.
+ }
+ have NEQf: optimism <= F_sp.
+ { by apply leq_trans with F. }
+ have NEQ1: task_lock_in_service tsk <= F_sp.
+ { by apply leq_trans with F. }
+ have CNEQ: t1 + (A + F  optimism) + job_last <= job_arrival j + R.
+ { apply leq_trans with (job_arrival j + (F  optimism) + job_last).
+ { rewrite leq_add2r addnBA; last by (apply leq_trans with F; [done  rewrite leq_addl]).
+ by rewrite /A !addnA subnKC // addnBA. }
+ { rewrite addnA leq_add2l.
+ apply leq_trans with (F_sp  optimism + job_last ); first by rewrite leq_add2r leq_sub2r.
+ apply leq_trans with (F_sp + (task_cost tsk  task_lock_in_service tsk)); last by done.
+ rewrite /optimism subnBA; last by apply PRT2.
+ rewrite subh1 //.
+ rewrite /job_last.
+ rewrite addnBA; last by auto.
+ rewrite subh1; last by rewrite leq_addl.
+ rewrite addnBA // subnn addn0.
+ rewrite addnBA; last by auto.
+ rewrite subh1; last by done.
+ rewrite leq_sub2r // leq_add2l.
+ by rewrite H_job_of_tsk; apply H_job_cost_le_task_cost.
+ }
+ }
+ apply CONTRc.
+ apply completion_monotonic with
+ (t1 + ((A + F)  optimism) + job_last); try done.
+ apply negbNE; apply/negP; intros NCOMPL.
+ have ESERV :=
+ j_receives_at_least_lock_in_service
+ job_arrival job_cost
+ job_task arr_seq sched tsk
+ interference interfering_workload
+ _ j _ _ _ t1 t2 _ (job_lock_in_service j) _ ((A + F)  optimism).
+ feed_n 7 ESERV; eauto 2.
+ { rewrite {2}FIX2.
+ rewrite /AbstractRTADefinitions.cumul_interference.
+ rewrite [in X in _ <= X]subh1; last by rewrite leq_subr.
+ rewrite {2}/optimism.
+ rewrite subKn; last by auto.
+ rewrite leq_add2l.
+ apply leq_trans with (cumul_interference j t1 (t1 + (A + F))).
+ { rewrite /cumul_interference /AbstractRTADefinitions.cumul_interference;
+ rewrite [in X in _ <= X](@big_cat_nat _ _ _ (t1 + (A + F  optimism))) //=.
+ by rewrite leq_add2l leq_subr. }
+ { apply H_job_interference_is_bounded with t2; try done.
+  by rewrite EQSUM.
+  apply/negP; intros CONTR; apply: CONTRc.
+ apply completion_monotonic with (t1 + (A + F)); try done.
+ rewrite addnA subnKC // leq_add2l.
+ apply leq_trans with F_sp; first by done.
+ by apply leq_trans with (F_sp + (task_cost tsk  task_lock_in_service tsk)).
+ }
+ }
+ move: NCOMPL => /negP NCOMPL; apply: NCOMPL.
+ by eapply job_completes_after_reaching_lock_in_service; eauto.
+ Qed.
+
+ End FixpointIsNoLessThanArrival.
+
+ (* CASE 2: the value of the fixpoint is less than the relative arrival time of
+ job j (which turns out to be impossible, i.e. the solution of the responcetime
+ recurrense is always equal to or greater than the relative arrival time). *)
+ Section FixpointCannotBeSmallerThanArrival.
+
+ (* Assume that [A_sp + F_sp] is less than A. *)
+ Hypothesis H_fixpoint_is_less_that_relative_arrival_of_j: A_sp + F_sp < A.
+
+ (* Note that the relative arrival time of job j is less than L. *)
+ Lemma relative_arrival_is_bounded: A < L.
+ Proof.
+ rewrite /A.
+ move: (H_busy_interval_exists j H_j_arrives H_job_of_tsk H_job_cost_positive) => [t1' [t2' [_ [BOUND BUSY]]]].
+ have EQ:= busy_interval_is_unique _ _ _ _ _ _ _ _ _ _ H_busy_interval BUSY. destruct EQ as [EQ1 EQ2].
+ subst t1' t2'; clear BUSY.
+ apply leq_trans with (t2  t1); last by rewrite leq_subLR.
+ move: (H_busy_interval)=> [[/andP [H1 H3] [_ _]] _].
+ by apply ltn_sub2r; first apply leq_ltn_trans with (job_arrival j).
+ Qed.
+
+ (* We can use [j_receives_at_least_lock_in_service] to prove that the service
+ received by j by time [t1 + (A_sp + F_sp)] is no less than lock_in_service. *)
+ Lemma service_of_job_ge_lock_in_service:
+ service sched j (t1 + (A_sp + F_sp)) >= job_lock_in_service j.
+ Proof.
+ move: H_proper_job_lock_in_service => [PRJ1 [PRJ2 PRJ3]].
+ move: H_proper_task_lock_in_service => [PRT1 PRT2].
+ move: (H_busy_interval) => [[NEQ [QT1 NTQ]] QT2].
+ move: (NEQ) => /andP [GT LT].
+ move: (H_job_interference_is_bounded t1 t2 (A_sp + F_sp) j) => IB.
+ feed_n 5 IB; try done.
+ { apply/negP; intros COMPL.
+ apply completion_monotonic with (t' := t1 + A) in COMPL; try done; last first.
+ { by rewrite leq_add2l; apply ltnW. }
+ { rewrite /A subnKC in COMPL; last by done.
+ move: COMPL; rewrite /completed_by leqNgt; move => /negP COMPL; apply: COMPL.
+ rewrite /service (service_during_cat _ _ (job_arrival j)); last by apply/andP; split.
+ rewrite /service_during (cumulative_service_before_job_arrival_zero job_arrival) // add0n.
+ by rewrite big_geq //.
+ }
+ }
+ rewrite /A in IB.
+ have ALTT := relative_arrival_is_bounded.
+ simpl in IB; rewrite H_equivalent in IB; last by apply ltn_trans with A.
+ have ESERV := j_receives_at_least_lock_in_service
+ job_arrival job_cost
+ job_task arr_seq sched tsk
+ interference interfering_workload _ j _ _ _ t1 t2 _ (job_lock_in_service j) _ (A_sp + F_sp).
+ feed_n 7 ESERV; eauto 2.
+ by rewrite {2}H_fixpoint leq_add //; eapply PRT2.
+ Qed.
+
+ (* However, this is a contradiction. Since job j has not yet arrived, its
+ service it equal to 0. However, lock_in_service is always positive. *)
+ Lemma relative_arrival_time_is_no_less_than_fixpoint:
+ False.
+ Proof.
+ move: H_proper_job_lock_in_service => [PRJ1 [PRJ2 PRJ3]].
+ move: H_proper_task_lock_in_service => [PRT1 PRT2].
+ move: (H_busy_interval) => [[NEQ [QT1 NTQ]] QT2].
+ move: (NEQ) => /andP [GT LT].
+ have ESERV := service_of_job_ge_lock_in_service.
+ move: ESERV; rewrite leqNgt; move => /negP ESERV; apply: ESERV.
+ rewrite /service /service_during (cumulative_service_before_job_arrival_zero job_arrival); auto.
+ rewrite [X in _ <= X](@subnKC t1); last by done.
+ by rewrite /A leq_add2l ltnW.
+ Qed.
+
+ End FixpointCannotBeSmallerThanArrival.
+
+ End FixpointInsideBusyInterval.
+
+ End ProofOfTheorem.
+
+ (* Using the lemmas above, we prove that R is a responsetime bound. *)
+ Theorem uniprocessor_response_time_bound:
+ response_time_bounded_by tsk R.
+ Proof.
+ intros j ARR JOBtsk.
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { by rewrite /is_response_time_bound_of_job /completed_by ZERO. }
+ move: (H_busy_interval_exists j ARR JOBtsk POS) => [t1 [t2 [NEQ [H2 BUSY]]]].
+ move: (NEQ) (BUSY)=> /andP [GE LT] [_ QTt2].
+ have A2LTL := relative_arrival_is_bounded _ ARR JOBtsk POS _ _ BUSY.
+ set (A2 := job_arrival j  t1) in *.
+ move: (representative_exists tsk _ interference_bound_function _ A2LTL) => [A1 [ALEA2 [EQΦ INSP]]].
+ move: (H_R_is_maximum _ INSP) => [F1 [FIX1 LE1]].
+ destruct (t1 + (A1 + F1) >= t2) eqn:BIG.
+  eapply job_completed_by_arrival_plus_R_1; eauto 2.
+  apply negbT in BIG; rewrite ltnNge in BIG.
+ destruct (A2 <= A1 + F1) eqn:BOUND.
+ + eapply job_completed_by_arrival_plus_R_2; eauto 2.
+ + apply negbT in BOUND; rewrite ltnNge in BOUND.
+ exfalso; eapply relative_arrival_time_is_no_less_than_fixpoint; eauto 2.
+ Qed.
+
+ End Abstract_RTA.
+
+End AbstractRTA.
diff git a/model/schedule/uni/limited/abstract_RTA/abstract_seq_rta.v b/model/schedule/uni/limited/abstract_RTA/abstract_seq_rta.v
new file mode 100644
index 0000000000000000000000000000000000000000..45783244467b94347af01b6f807157e515e1ac15
 /dev/null
+++ b/model/schedule/uni/limited/abstract_RTA/abstract_seq_rta.v
@@ 0,0 +1,639 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time
+ rt.model.schedule.uni.schedule_of_task.
+Require Import rt.model.schedule.uni.limited.rbf
+ rt.model.schedule.uni.limited.schedule.
+Require Import rt.model.arrival.curves.bounds.
+Require Import rt.analysis.uni.arrival_curves.workload_bound.
+Require Import rt.model.schedule.uni.limited.abstract_RTA.definitions
+ rt.model.schedule.uni.limited.abstract_RTA.sufficient_condition_for_lock_in_service
+ rt.model.schedule.uni.limited.abstract_RTA.reduction_of_search_space
+ rt.model.schedule.uni.limited.abstract_RTA.abstract_rta.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Abstract ResponseTime Analysis with sequential jobs *)
+(** In this module we propose the general framework for responsetime analysis (RTA)
+ of uniprocessor scheduling of realtime tasks with arbitrary arrival models
+ and sequential jobs. *)
+Module AbstractSeqRTA.
+
+ Import Job Epsilon ArrivalCurves TaskArrival ScheduleOfTask UniprocessorSchedule Workload
+ Service ResponseTime MaxArrivalsWorkloadBound
+ AbstractRTADefinitions AbstractRTALockInService AbstractRTAReduction AbstractRTA.
+
+ (* In this section we prove that the maximum among the solutions of
+ the responsetime bound recurrence for some set of parameters
+ is a responsetime bound for tsk. Note that in this section we _do_
+ rely on the hypothesis about job sequentiality. This allows us to
+ provide a more precise responsetime bound function, since jobs of
+ the same task will be executed strictly in the order they arrive. *)
+ Section Sequential_Abstract_RTA.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence... *)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Assume that the job costs are no larger than the task costs. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_pending_at := pending job_arrival job_cost sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let task_scheduled_at := task_scheduled_at job_task sched.
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+
+ (* Consider an arbitrary task set. *)
+ Variable ts: list Task.
+
+ (* In addition, assume that all jobs come from the task set. *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Consider proper job lockin service and task lockin functions, i.e... *)
+ Variable job_lock_in_service: Job > time.
+ Variable task_lock_in_service: Task > time.
+
+ (* ...we assume that for all jobs in the arrival sequence the lockin service is
+ (1) positive, (2) no bigger than costs of the corresponding jobs, and (3) a job
+ becomes nonpreemptive after it reaches its lockin service... *)
+ Hypothesis H_proper_job_lock_in_service:
+ proper_job_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* ...and that [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any
+ job of task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Hypothesis H_proper_task_lock_in_service:
+ proper_task_lock_in_service
+ task_cost job_task arr_seq job_lock_in_service task_lock_in_service tsk.
+
+ (* Assume we are provided with abstract functions for interference and interfering workload. *)
+ Variable interference: Job > time > bool.
+ Variable interfering_workload: Job > time > time.
+
+ (* Let's define some local names for clarity. *)
+ Let task_rbf := task_request_bound_function task_cost max_arrivals tsk.
+ Let work_conserving := work_conserving job_arrival job_cost job_task arr_seq sched tsk.
+ Let busy_intervals_are_bounded_by := busy_intervals_are_bounded_by job_arrival job_cost job_task arr_seq sched tsk.
+ Let job_interference_is_bounded_by := job_interference_is_bounded_by job_arrival job_cost job_task arr_seq sched tsk.
+ Let busy_interval := busy_interval job_arrival job_cost sched interference interfering_workload.
+ Let task_workload_between := task_workload_between job_cost job_task arr_seq tsk.
+ Let arrivals_of_task_before := arrivals_of_task_before job_task arr_seq.
+ Let task_service_between := task_service_between job_task arr_seq sched tsk.
+
+ (* In this section, we introduce a few new definitions to make it easier to
+ express the new bound of the worstcase execution time. *)
+ Section Definitions.
+
+ (* When assuming sequential jobs, we can introduce an additional hypothesis that
+ ensures that the values of interference and workload remain consistent. It states
+ that any of tsk's job, that arrived before the busy interval, should be
+ completed by the beginning of the busy interval. *)
+ Definition interference_and_workload_consistent_with_sequential_jobs :=
+ forall j t1 t2,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ job_cost j > 0 >
+ busy_interval j t1 t2 >
+ task_workload_between 0 t1 = task_service_between 0 t1.
+
+ (* Next we introduce the notion of task interference. Intuitively, task tsk incurs interference
+ when some of the jobs of task tsk incur interference. As a result, tsk cannot make any progress.
+
+ More formally, task tsk experiences interference at a time instant time t, if at time t
+ task tsk is not scheduled and there exists a job of tsk that (1) experiences interference and
+ (2) has arrived before some time instant [upper_bound].
+
+ It is important to note two subtle points: according to our semantics of the interference function,
+ jobs from the same task can cause interference to each other. In the definition of interference of
+ a task we want to avoid such situations. That is why we use the term [~~ task_scheduled_at tsk t].
+
+ Moreover, in order to make the definition constructive, we introduce an upper
+ bound on the arrival time of jobs from task tsk. As a result, we need to consider only a finite
+ number of jobs. For the function to produce the correct values it is enough to specify
+ a sufficiently large upper_bound. Usually as upper_bound one can use the end
+ of the corresponding busy interval. *)
+ Definition task_interference_received_before (tsk: Task) (upper_bound: time) (t: time) :=
+ (~~ task_scheduled_at tsk t)
+ && has (fun j => interference j t) (arrivals_of_task_before tsk upper_bound).
+
+ (* Next we define the cumulative task interference. *)
+ Definition cumul_task_interference tsk upper_bound t1 t2 :=
+ \sum_(t1 <= t < t2) task_interference_received_before tsk upper_bound t.
+
+ (* We say that task interference is bounded by task_interference_bound_function (tIBF)
+ iff for any job j of task tsk cumulative _task_ interference within the interval
+ [t1, t1 + R) is bounded by function tIBF(tsk, A, R).
+ Note that this definition is almost the same as the definition of job_interference_is_bounded_by
+ from the nonnesessarysequential case. However, in this case we ignore the
+ interference that comes from jobs from the same task. *)
+ Definition task_interference_is_bounded_by (task_interference_bound_function: Task > time > time > time) :=
+ forall j R t1 t2,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ t1 + R < t2 >
+ ~~ job_completed_by j (t1 + R) >
+ busy_interval j t1 t2 >
+ let offset := job_arrival j  t1 in
+ cumul_task_interference tsk t2 t1 (t1 + R) <= task_interference_bound_function tsk offset R.
+
+ End Definitions.
+
+ (* In this section, we prove that the maximum among the solutions of the
+ responsetime bound recurrence is a responsetime bound for tsk. *)
+ Section ResponseTimeBound.
+
+ (* For simplicity, let's define some local names. *)
+ Let cumul_interference := cumul_interference interference.
+ Let cumul_workload := cumul_interfering_workload interfering_workload.
+ Let cumul_task_interference := cumul_task_interference tsk.
+
+ (* We assume that the schedule is workconserving. *)
+ Hypothesis H_work_conserving: work_conserving interference interfering_workload.
+
+ (* Unlike the previous theorem [uniprocessor_response_time_bound], we assume
+ that (1) jobs are sequential, moreover (2) functions interference and
+ interfering_workload are consistent with the hypothesis of sequential jobs. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+ Hypothesis H_interference_and_workload_consistent_with_sequential_jobs:
+ interference_and_workload_consistent_with_sequential_jobs.
+
+ (* Assume we have a constant L which bounds the busy interval of any of tsk's jobs. *)
+ Variable L: time.
+ Hypothesis H_busy_interval_exists: busy_intervals_are_bounded_by interference interfering_workload L.
+
+ (* Next, we assume that task_interference_bound_function is a bound on interference incurred by the task. *)
+ Variable task_interference_bound_function: Task > time > time > time.
+ Hypothesis H_task_interference_is_bounded: task_interference_is_bounded_by task_interference_bound_function.
+
+ (* Given any job j of task tsk that arrives exactly A units after the beginning of the busy
+ interval, the bound on the total interference incurred by j within an interval of length Δ
+ is no greater than [task_rbf (A + ε)  task_cost tsk + task's IBF Δ]. Note that in case of
+ sequential jobs the bound consists of two parts: (1) the part that bounds the interference
+ received from other jobs of task tsk  [task_rbf (A + ε)  task_cost tsk] and (2) any other
+ interferece that is bounded by task_IBF(tsk, A, Δ). *)
+ Let total_interference_bound tsk A Δ :=
+ task_rbf (A + ε)  task_cost tsk + task_interference_bound_function tsk A Δ.
+
+ (* Note that since we consider the modified interference bound function, the search space has
+ also changed. One can see that the new search space is guaranteed to include any A for which
+ [task_rbf (A) ≠ task_rbf (A + ε)], since this implies the fact that
+ [total_interference_bound (tsk, A, Δ) ≠ total_interference_bound (tsk, A + ε, Δ)]. *)
+ Let is_in_search_space_seq := is_in_search_space tsk L total_interference_bound.
+
+ (* Consider any value R, and assume that for any relative arrival time A from the search
+ space there is a solution F of the responsetime recurrence that is bounded by R. In
+ contrast to the formula in "nonsequential" Abstract RTA, assuming that jobs are
+ sequential leads to a more precise responsetime bound. Now we can explicitly express
+ the interference caused by other jobs of the task under consideration.
+
+ To understand the right part of the fixpoint in the equation it is helpful to note
+ that the bound on the total interference (bound_of_total_interference) is equal to
+ [task_rbf (A + ε)  task_cost tsk + tIBF tsk A Δ]. Besides, a job must receive
+ enough service to become nonpreemptive [task_lock_in_service tsk]. The sum of
+ these two quantities is exactly the righthand side of the equation. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum_seq:
+ forall A,
+ is_in_search_space_seq A >
+ exists F,
+ A + F = (task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk))
+ + task_interference_bound_function tsk A (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+ (* In this section we prove a few simple lemmas about the completion of jobs from the task
+ considering the busy interval of the job under consideration. *)
+ Section CompletionOfJobsFromSameTask.
+
+ (* Consider any two jobs j1 j2 of tsk. *)
+ Variable j1 j2: Job.
+ Hypothesis H_j1_arrives: arrives_in arr_seq j1.
+ Hypothesis H_j2_arrives: arrives_in arr_seq j2.
+ Hypothesis H_j1_from_tsk: job_task j1 = tsk.
+ Hypothesis H_j2_from_tsk: job_task j2 = tsk.
+ Hypothesis H_j1_cost_positive: job_cost_positive job_cost j1.
+
+ (* Consider the busy interval [t1, t2) of job j1. *)
+ Variable t1 t2: time.
+ Hypothesis H_busy_interval: busy_interval j1 t1 t2.
+
+ (* We prove that if a job from task tsk arrived before the beginning of the busy
+ interval, then it must be completed before the beginning of the busy interval *)
+ Lemma completed_before_beginning_of_busy_interval:
+ job_arrival j2 < t1 >
+ completed_by job_cost sched j2 t1.
+ Proof.
+ move => JA; move: (H_j2_from_tsk) => /eqP TSK2eq.
+ move: (posnP (job_cost j2)) => [ZEROPOS].
+ { by rewrite /is_response_time_bound_of_job /completed_by ZERO. }
+ move: (H_interference_and_workload_consistent_with_sequential_jobs
+ j1 t1 t2 H_j1_arrives H_j1_from_tsk H_j1_cost_positive H_busy_interval) => SWEQ.
+ eapply all_jobs_have_completed_equiv_workload_eq_service
+ with (j := j2) in SWEQ; eauto 2; try done.
+ by apply arrived_between_implies_in_arrivals with job_arrival.
+ Qed.
+
+ (* Next we prove that if a job is pending after the beginning
+ of the busy interval [t1, t2) then it arrives after t1 . *)
+ Lemma arrives_after_beginning_of_busy_interval:
+ forall t,
+ t1 <= t >
+ job_pending_at j2 t >
+ arrived_between job_arrival j2 t1 t.+1.
+ Proof.
+ intros t GE PEND.
+ rewrite /arrived_between; apply/andP; split; last first.
+ { by move: PEND => /andP [ARR _]; rewrite ltnS. }
+ rewrite leqNgt; apply/negP; intros LT.
+ move: (H_busy_interval) => [[/andP [AFR1 AFR2] [QT _]] _].
+ have L12 := completed_before_beginning_of_busy_interval.
+ feed L12; try done.
+ apply completion_monotonic with (t' := t) in L12; try done.
+ by move: PEND => /andP [_ /negP H2].
+ Qed.
+
+ End CompletionOfJobsFromSameTask.
+
+ (* Since we are going to use the [uniprocessor_response_time_bound] theorem to prove
+ the theorem of this section, we have to show that all the hypotheses are satisfied.
+ Namely, we need to show that hypotheses [H_sequential_jobs, H_i_w_are_task_consistent
+ and H_task_interference_is_bounded_by] imply [H_job_interference_is_bounded], and the
+ fact that [H_R_is_maximum_seq] implies [H_R_is_maximum]. *)
+
+ (* In this section we show that there exists a bound for cumulative interference for any
+ job of task tsk, i.e., the hypothesis H_job_interference_is_bounded holds. *)
+ Section BoundOfCumulativeJobInterference.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Consider the busy interval [t1, t2) of job j. *)
+ Variable t1 t2: time.
+ Hypothesis H_busy_interval: busy_interval j t1 t2.
+
+ (* Let's define A as a relative arrival time of job j (with respect to time t1). *)
+ Let A := job_arrival j  t1.
+
+ (* Consider an arbitrary time x... *)
+ Variable x: time.
+ (* ...such that (t1 + x) is inside the busy interval... *)
+ Hypothesis H_inside_busy_interval: t1 + x < t2.
+ (* ... and job j is not completed by time (t1 + x). *)
+ Hypothesis H_job_j_is_not_completed: ~~ job_completed_by j (t1 + x).
+
+ (* We start by proving that the cumulative interference incurred by job j is bounded by the sum of
+ the task workload on the interval [t1, t1 + A] and the cumulative interference of j's task. *)
+ Lemma bound_for_cumulative_job_interference_actual:
+ cumul_interference j t1 (t1 + x) <=
+ (task_workload_between t1 (t1 + A + ε)  job_cost j) + cumul_task_interference t2 t1 (t1 + x).
+ Proof.
+ set (y := t1 + x) in *.
+ have IN: j \in arrivals_between t1 (t1 + A + ε).
+ { eapply arrived_between_implies_in_arrivals; eauto 2.
+ move: (H_busy_interval) => [[/andP [GE _] [_ _]] _].
+ by apply/andP; split; last rewrite /A subnKC // addn1.
+ }
+ have Fact1:
+ task_service_of_jobs_received_in job_task arr_seq sched tsk t1 (t1 + A + ε) t1 y
+  service_during sched j t1 y <=
+ task_workload_between t1 (t1 + A + ε)  job_cost j.
+ { rewrite /task_workload /task_service_of_jobs_received_in /service_of_jobs /workload_of_jobs.
+ rewrite (big_rem j) ?[X in _ <= X  _](big_rem j) //=.
+ rewrite H_job_of_tsk eq_refl.
+ rewrite addnC addnBA; last by done.
+ rewrite [X in _ <= X  _]addnC addnBA; last by done.
+ rewrite !subnn !addn0.
+ by apply service_of_jobs_le_workload.
+ }
+ apply leq_trans with (
+ task_service_of_jobs_received_in job_task arr_seq sched tsk t1 (t1+A+ε) t1 y
+  service_during sched j t1 y
+ + cumul_task_interference t2 t1 y); [clear Fact1  by rewrite leq_add2r].
+ rewrite /cumul_interference /cumul_interference
+ /task_service_of_jobs_received_in /service_of_jobs /service_during exchange_big //=
+ /cumul_task_interference /Sequential_Abstract_RTA.cumul_task_interference.
+ rewrite (leq_add2r (\sum_(t1 <= t < y) service_at sched j t)).
+ rewrite [X in _ <= X]addnC addnA subnKC; last first.
+ { by rewrite exchange_big //= (big_rem j) //= H_job_of_tsk eq_refl leq_addr. }
+ rewrite big_split big_split //=.
+ rewrite big_nat_cond [X in _ <= X]big_nat_cond leq_sum //; move => t /andP [NEQ _].
+ have Fact1:
+ service_at sched j t <= \sum_(i0 < arrivals_between t1 (t1 + A + ε)  job_task i0 == tsk) service_at sched i0 t.
+ { by rewrite (big_rem j) // H_job_of_tsk eq_refl leq_addr. }
+ unfold task_scheduled_at, ScheduleOfTask.task_scheduled_at.
+ case SCHEDt: (sched t) => [s  ]; last first.
+ { rewrite {1}/service_at {1}/scheduled_at SCHEDt; simpl; rewrite addn0.
+ case INT: (interference j t); last by done.
+ apply leq_trans with (task_interference_received_before tsk t2 t); last by rewrite leq_addl.
+ rewrite lt0b.
+ rewrite /task_interference_received_before /task_scheduled_at /ScheduleOfTask.task_scheduled_at SCHEDt; simpl.
+ apply/hasP; exists j; last by done.
+ rewrite /arrivals_of_task_before mem_filter; apply/andP; split.
+  by rewrite /is_job_of_task H_job_of_tsk.
+  move: (H_busy_interval) => [[/andP [_ LT] [_ _]] _].
+ by eapply arrived_between_implies_in_arrivals; eauto.
+ }
+ have ARRs: arrives_in arr_seq s.
+ { by apply H_jobs_come_from_arrival_sequence with t; apply/eqP. }
+ case TSK: (job_task s == tsk); last first.
+ { have ZERO: service_at sched j t = 0.
+ { rewrite /service_at /scheduled_at SCHEDt.
+ apply/eqP; rewrite eqb0; apply/negP.
+ intros FALSE; move: FALSE => /eqP FALSE; inversion FALSE; subst s.
+ by move: TSK => /eqP TSK; apply TSK.
+ }
+ rewrite ZERO; clear ZERO.
+ have ZERO: \sum_(i < arrivals_between t1 (t1 + A + ε)  job_task i == tsk) service_at sched i t = 0.
+ { rewrite /service_at /scheduled_at SCHEDt.
+ apply big1; move => k /eqP TSK2.
+ apply/eqP; rewrite eqb0; apply/negP.
+ intros FALSE; move: FALSE => /eqP FALSE; inversion FALSE; subst s.
+ by move: TSK => /eqP TSK; apply TSK.
+ }
+ rewrite ZERO; clear ZERO.
+ rewrite addn0 add0n.
+ rewrite /task_interference_received_before /task_scheduled_at /ScheduleOfTask.task_scheduled_at.
+ rewrite SCHEDt TSK; simpl.
+ case INT: (interference j t); last by done.
+ rewrite lt0b.
+ apply/hasP; exists j; last by done.
+ rewrite /arrivals_of_task_before mem_filter; apply/andP; split.
+  by rewrite /is_job_of_task H_job_of_tsk.
+  move: (H_busy_interval) => [[/andP [_ LT] [_ _]] _].
+ by eapply arrived_between_implies_in_arrivals; eauto.
+ }
+ { rewrite /task_interference_received_before /task_scheduled_at /ScheduleOfTask.task_scheduled_at SCHEDt TSK.
+ simpl; rewrite addn0.
+ case EQ: (j == s).
+ { move: EQ => /eqP EQ; subst s.
+ move: (H_work_conserving j t1 t2 t H_j_arrives H_job_of_tsk H_job_cost_positive H_busy_interval) => WORK.
+ feed WORK.
+ { by move: NEQ => /andP [NEQ1 NEQ2]; apply/andP; split; last apply ltn_trans with y. }
+ move: WORK => [_ ZIJT].
+ feed ZIJT; first by rewrite /scheduled_at SCHEDt.
+ move: ZIJT => /negP /eqP; rewrite eqb_negLR; simpl; move => /eqP ZIJT.
+ rewrite ZIJT; simpl; rewrite add0n.
+ by done.
+ }
+ { have NSCHED: scheduled_at sched j t = false.
+ { apply/negP; intros SCHED.
+ move: SCHEDt => /eqP SCHEDt.
+ move: (only_one_job_scheduled sched j s t SCHED SCHEDt) => EQjs.
+ by rewrite EQjs eq_refl in EQ.
+ }
+ rewrite /service_at NSCHED.
+ have IJT: interference j t = true.
+ { have NEQT: t1 <= t < t2.
+ { move: NEQ => /andP [NEQ1 NEQ2].
+ apply/andP; split; first by done.
+ by apply ltn_trans with y.
+ }
+ move: (H_work_conserving j t1 t2 t H_j_arrives H_job_of_tsk H_job_cost_positive H_busy_interval NEQT) => [Hn _].
+ apply/negPn/negP; intros CONTR; move: CONTR => /negP CONTR.
+ by apply Hn in CONTR; rewrite NSCHED in CONTR.
+ }
+ rewrite IJT; clear IJT.
+ simpl. rewrite addn0.
+ rewrite big_mkcond; apply/sum_seq_gt0P.
+ exists s; split.
+ { intros. have ARR:= arrives_after_beginning_of_busy_interval j s _ _ _ _ _ t1 t2 _ t.
+ feed_n 8 ARR; try done.
+ { by move: TSK => /eqP TSK; rewrite TSK. }
+ { by move: NEQ => /andP [T1 T2]. }
+ { by move: SCHEDt => /eqP SCHEDt; apply scheduled_implies_pending. }
+ case ARRNEQ: (job_arrival s <= job_arrival j).
+ { move: ARR => /andP [РР _].
+ unfold arrivals_between in *.
+ eapply arrived_between_implies_in_arrivals; eauto 2.
+ apply/andP; split; first by done.
+ rewrite /A subnKC.
+ rewrite addn1 ltnS. by done.
+ by move: (H_busy_interval) => [[/andP [BUS _] _] _].
+ }
+ { exfalso.
+ apply negbT in ARRNEQ; rewrite ltnNge in ARRNEQ.
+ move: (H_sequential_jobs j s t) => CONTR.
+ feed_n 3 CONTR; try done.
+ { by rewrite H_job_of_tsk in TSK; rewrite eq_sym. }
+ { by move: SCHEDt => /eqP SCHEDt. }
+ move: H_job_j_is_not_completed => /negP H; apply: H.
+ apply completion_monotonic with t; try done.
+ apply ltnW.
+ by move: NEQ => /andP [_ NEQ].
+ }
+ }
+ { move: TSK => /eqP TSK.
+ by rewrite TSK eq_refl /service_at /scheduled_at SCHEDt eq_refl.
+ }
+ }
+ }
+ Qed.
+
+ (* However, in order to obtain a more convenient bound of the cumulative interference,
+ we need to abandon the actual workload in favor of a bound which depends on task parameters only.
+ So, we show that actual workload of the task excluding workload of any job j is no greater than
+ bound of workload excluding the cost of job j's task. *)
+ Lemma task_rbf_excl_tsk_bounds_task_workload_excl_j:
+ task_workload_between t1 (t1 + A + ε)  job_cost j <= task_rbf (A + ε)  task_cost tsk.
+ Proof.
+ unfold cost_of_jobs_from_arrival_sequence_le_task_cost, job_cost_le_task_cost in *.
+ move: H_j_arrives H_job_of_tsk => ARR TSK.
+ move: (H_busy_interval) => [[/andP [JAGET1 JALTT2] _] _].
+ apply leq_trans with (
+ task_cost tsk *
+ num_arrivals_of_task job_task arr_seq tsk t1 (t1 + A + ε)  task_cost tsk); last first.
+ { rewrite leq_sub2r //.
+ rewrite leq_mul2l; apply/orP; right.
+ rewrite addnA {2}[(A+1)](addKn t1).
+ move: (H_family_of_proper_arrival_curves tsk H_tsk_in_ts) => [ARRB T].
+ by apply ARRB; last rewrite leq_addr.
+ }
+ { have Fact6: j \in arrivals_between (t1 + A) (t1 + A + ε).
+ { apply (arrived_between_implies_in_arrivals job_arrival); try(done).
+ apply/andP; split; rewrite /A subnKC //.
+ by rewrite addn1 ltnSn //.
+ }
+ have Fact1: num_arrivals_of_task job_task arr_seq tsk (t1 + A) (t1 + A + ε) >= 1.
+ { rewrite /num_arrivals_of_task /arrivals_of_task_between.
+ rewrite count_filter_fun has_count; apply/hasP.
+ by exists j; last rewrite /is_job_of_task TSK.
+ }
+ have Fact2: job_cost j <= task_workload_between (t1 + A) (t1 + A + ε).
+ { rewrite /task_workload_between /Workload.task_workload_between /task_workload
+ /workload_of_jobs /arrivals_between (big_rem j) //=.
+ by rewrite TSK eq_refl leq_addr.
+ }
+ have Fact3: 0 < task_cost tsk.
+ { apply leq_trans with (job_cost j); [ rewrite H_job_of_tsk]; auto. }
+ have Fact4: j \in jobs_arriving_at arr_seq (t1 + A).
+ { move: ARR => [t ARR]; rewrite subnKC //.
+ by feed (H_arrival_times_are_consistent j t); try (subst t).
+ }
+ rewrite (@num_arrivals_of_task_cat _ _ _ _ _ (t1 + A)); last by apply/andP; split; rewrite leq_addr //.
+ rewrite mulnDr.
+ have Step1:
+ task_workload_between t1 (t1 + A + ε) = task_workload_between t1 (t1 + A) + task_workload_between (t1 + A) (t1 + A + ε).
+ { by apply workload_of_jobs_cat; apply/andP; split; rewrite leq_addr. }
+ rewrite Step1; clear Step1.
+ rewrite !addnBA; first last.
+ { by apply leq_trans with (job_cost j). }
+ { apply leq_trans with (task_cost tsk); first by done.
+ by rewrite {1}[task_cost tsk]muln1 leq_mul2l; apply/orP; right. }
+ rewrite leq_add; first by done.
+ { rewrite // /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /task_workload_between /Workload.task_workload_between /task_workload /workload_of_jobs.
+ rewrite /is_job_of_task TSK muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ by rewrite EQ; apply in_arrivals_implies_arrived in IN0; auto.
+ }
+ { unfold task_workload_between, Workload.task_workload_between,
+ task_workload, workload_of_jobs, arrivals_between, jobs_arrived_between.
+ rewrite {1}addn1 big_nat1.
+ rewrite /num_arrivals_of_task /arrivals_of_task_between /jobs_arrived_between addn1 big_nat1.
+ rewrite (big_rem j) //= TSK !eq_refl; simpl.
+ rewrite addnC addnBA; last by done.
+ rewrite subnn addn0.
+ rewrite (filter_size_rem _ j); [  by done  by rewrite /is_job_of_task TSK].
+ rewrite mulnDr mulnC muln1 addnBA; last by done.
+ rewrite subnn addn0.
+ rewrite mulnC.
+ apply sum_majorant_constant.
+ move => j' ARR' /eqP TSK2.
+ unfold job_cost_le_task_cost in *.
+ have ARR2: arrives_in arr_seq j'.
+ { by exists (t1 + A); apply rem_in in ARR'. }
+ by rewrite TSK2; auto.
+ }
+ }
+ Qed.
+
+ (* Now we can use two lemmas above to get the following bound: *)
+ Lemma bound_for_cumulative_job_interference:
+ cumul_interference j t1 (t1 + x)
+ <= (task_rbf (A + ε)  task_cost tsk) + cumul_task_interference t2 t1 (t1 + x).
+ Proof.
+ set (y := t1 + x) in *.
+ have IN: j \in arrivals_between t1 (t1 + A + ε).
+ { eapply arrived_between_implies_in_arrivals; eauto 2.
+ move: (H_busy_interval) => [[/andP [GE _] _] _].
+ by apply/andP; split; last rewrite /A subnKC // addn1.
+ }
+ apply leq_trans with (task_workload_between t1 (t1+A+ε)  job_cost j + cumul_task_interference t2 t1 y).
+  by apply bound_for_cumulative_job_interference_actual.
+  rewrite leq_add2r.
+ eapply task_rbf_excl_tsk_bounds_task_workload_excl_j; eauto 2.
+ Qed.
+
+ End BoundOfCumulativeJobInterference.
+
+ (* In this section, we prove that [H_R_is_maximum_seq] implies [H_R_is_maximum]. *)
+ Section MaxInSeqHypothesisImpMaxInNonseqHypothesis.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+
+ (* For simplicity, let's define a local name for the search space. *)
+ Let is_in_search_space A :=
+ is_in_search_space tsk L total_interference_bound A.
+
+ (* We prove that [H_R_is_maximum] holds. *)
+ Lemma max_in_seq_hypothesis_implies_max_in_nonseq_hypothesis:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = task_lock_in_service tsk +
+ (task_rbf (A + ε)  task_cost tsk + task_interference_bound_function tsk A (A + F)) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+ Proof.
+ move: H_proper_job_lock_in_service => [PRJ1 [PRJ2 PRJ3]].
+ move: H_proper_task_lock_in_service => [PRT1 PRT2].
+ intros A INSP.
+ clear H_sequential_jobs H_interference_and_workload_consistent_with_sequential_jobs.
+ move: (H_R_is_maximum_seq _ INSP) => [F [FIX LE]].
+ exists F; split; last by done.
+ rewrite {1}FIX.
+ apply/eqP.
+ rewrite addnA eqn_add2r.
+ rewrite addnBA; last first.
+ { apply leq_trans with (task_rbf 1).
+ eapply rbf.RBF.task_rbf_1_ge_task_cost; eauto 2.
+ eapply rbf.RBF.task_rbf_monotone; eauto 2.
+ by rewrite addn1. }
+ by rewrite subnBA; auto; rewrite addnC.
+ Qed.
+
+ End MaxInSeqHypothesisImpMaxInNonseqHypothesis.
+
+ (* Finally, we apply the [uniprocessor_response_time_bound] theorem, and using the
+ lemmas above, we prove that all the requirements are satisfied. So, R is a response
+ time bound. *)
+ Theorem uniprocessor_response_time_bound_seq:
+ response_time_bounded_by tsk R.
+ Proof.
+ intros j ARR TSK.
+ eapply uniprocessor_response_time_bound with
+ (interference_bound_function := fun tsk A R => task_rbf (A + ε)  task_cost tsk + task_interference_bound_function tsk A R)
+ (interfering_workload0 := interfering_workload); eauto 2.
+ { clear ARR TSK H_R_is_maximum_seq R j.
+ intros t1 t2 R j BUSY NEQ ARR TSK COMPL.
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { exfalso.
+ move: COMPL => /negP COMPL; apply: COMPL.
+ by rewrite /is_response_time_bound_of_job /completed_by ZERO.
+ }
+ set (A := job_arrival j  t1) in *.
+ apply leq_trans with
+ (task_rbf (A + ε)  task_cost tsk + cumul_task_interference t2 t1 (t1 + R)).
+  by eapply bound_for_cumulative_job_interference; eauto 2.
+  by rewrite leq_add2l; apply H_task_interference_is_bounded.
+ }
+ { by eapply max_in_seq_hypothesis_implies_max_in_nonseq_hypothesis; eauto. }
+ Qed.
+
+ End ResponseTimeBound.
+
+ End Sequential_Abstract_RTA.
+
+End AbstractSeqRTA.
+
\ No newline at end of file
diff git a/model/schedule/uni/limited/abstract_RTA/definitions.v b/model/schedule/uni/limited/abstract_RTA/definitions.v
new file mode 100644
index 0000000000000000000000000000000000000000..2bf00e6268df35a3e66c86e8823b700545af75a5
 /dev/null
+++ b/model/schedule/uni/limited/abstract_RTA/definitions.v
@@ 0,0 +1,224 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job.
+Require Import rt.model.schedule.uni.schedule.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Definitions for Abstract ResponseTime Analysis *)
+(** In this module, we propose a set of definitions for the general framework for responsetime analysis (RTA)
+ of uniprocessor scheduling of realtime tasks with arbitrary arrival models. *)
+Module AbstractRTADefinitions.
+
+ Import Job Epsilon UniprocessorSchedule.
+
+ (* In this section, we introduce all the abstract notions required by the analysis. *)
+ Section Definitions.
+
+ Context {Task: eqType}.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ... and any uniprocessor schedule of this arrival sequence. *)
+ Variable sched: schedule Job.
+
+ (* Let tsk be any task that is to be analyzed *)
+ Variable tsk: Task.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+
+ (* Recall that a job j is pending_earlier_and_at a time instant t iff job
+ j arrived before time t and is still not completed by time t. *)
+ Let job_pending_earlier_and_at := pending_earlier_and_at job_arrival job_cost sched.
+
+ (* We are going to introduce two main variables of the analysis:
+ (a) interference, and (b) interfering workload. *)
+
+ (** a) Interference *)
+ (* Execution of a job may be postponed by the environment and/or the system due to different
+ factors (preemption by higherpriority jobs, jitter, blackout periods in hierarchical
+ scheduling, lack of budget, etc.), which we call interference.
+
+ Besides, note that even the n’th activation of a task can suffer from interference at
+ the beggining of its busy interval (despite the fact that this job hasn’t even arrived
+ at that moment!). Thus, it makes more sense (at least for the current busyinterval
+ analysis) to think about interference of a job as any interference within the
+ corresponding busy interval, and not after release of the job.
+
+ Based on that, assume a predicate that expresses whether a job j under consideration
+ incurs interference at a given time t (in the context of the schedule under consideration).
+ This will be used later to upperbound job j's response time. Note that a concrete
+ realization of the function may depend on the schedule, but here we do not require this
+ for the sake of simplicity and generality. *)
+ Variable interference: Job > time > bool.
+
+ (** b) Interfering Workload *)
+ (* In addition to interference, the analysis assumes that at any time t, we know an upper
+ bound on the potential cumulative interference that can be incurred in the future by any
+ job (i.e., the total remaining potential delays). Based on that, assume a function
+ interfering_workload that indicates for any job j, at any time t, the amount of potential
+ interference for job j that is introduced into the system at time t. This function will be
+ later used to upperbound the length of the busy window of a job.
+ One example of workload function is the "total cost of jobs that arrive at time t and
+ have higherorequal priority than job j". In some task models, this function expresses
+ the amount of the potential interference on job j that "arrives" in the system at time t. *)
+ Variable interfering_workload: Job > time > time.
+
+ (* In order to bound the response time of a job, we must to consider the cumulative
+ interference and cumulative interfering workload. *)
+ Definition cumul_interference j t1 t2 := \sum_(t1 <= t < t2) interference j t.
+ Definition cumul_interfering_workload j t1 t2 := \sum_(t1 <= t < t2) interfering_workload j t.
+
+ (** Definition of Busy Interval *)
+ (* Further analysis will be based on the notion of a busy interval. The overall idea of the
+ busy interval is to take into account the workload that cause a job under consideration to
+ incur interference. In this section, we provide a definition of an abstract busy interval. *)
+ Section BusyInterval.
+
+ (* We say that time instant t is a quiet time for job j iff two conditions hold.
+ First, the cumulative interference at time t must be equal to the cumulative
+ interfering workload, to indicate that the potential interference seen so far
+ has been fully "consumed" (i.e., there is no more higherpriority work or other
+ kinds of delay pending). Second, job j cannot be pending at any time earlier
+ than t _and_ at time instant t (i.e., either it was pending earlier but is no
+ longer pending now, or it was previously not pending and may or may not be
+ released now), to ensure that the busy window captures the execution of job j. *)
+ Definition quiet_time (j: Job) (t: time) :=
+ cumul_interference j 0 t = cumul_interfering_workload j 0 t /\
+ ~~ job_pending_earlier_and_at j t.
+
+ (* Based on the definition of quiet time, we say that interval [t1, t2) is
+ a (potentially unbounded) busyinterval prefix w.r.t. job j iff the
+ interval (a) contains the arrival of job j, (b) starts with a quiet
+ time and (c) remains nonquiet. *)
+ Definition busy_interval_prefix (j: Job) (t1 t2: time) :=
+ t1 <= job_arrival j < t2 /\
+ quiet_time j t1 /\
+ (forall t, t1 < t < t2 > ~ quiet_time j t).
+
+ (* Next, we say that an interval [t1, t2) is a busy interval iff
+ [t1, t2) is a busyinterval prefix and t2 is a quiet time. *)
+ Definition busy_interval (j: Job) (t1 t2: time) :=
+ busy_interval_prefix j t1 t2 /\
+ quiet_time j t2.
+
+ (* Note that the busy interval, if it exists, is unique. *)
+ Lemma busy_interval_is_unique:
+ forall j t1 t2 t1' t2',
+ busy_interval j t1 t2 >
+ busy_interval j t1' t2' >
+ t1 = t1' /\ t2 = t2'.
+ Proof.
+ intros ? ? ? ? ? BUSY BUSY'.
+ have EQ: t1 = t1'.
+ { apply/eqP.
+ apply/negPn/negP; intros CONTR.
+ move: BUSY => [[IN [QT1 NQ]] _].
+ move: BUSY' => [[IN' [QT1' NQ']] _].
+ move: CONTR; rewrite neq_ltn; move => /orP [LTGT].
+ { apply NQ with t1'; try done; clear NQ.
+ apply/andP; split; first by done.
+ move: IN IN' => /andP [_ T1] /andP [T2 _].
+ by apply leq_ltn_trans with (job_arrival j).
+ }
+ { apply NQ' with t1; try done; clear NQ'.
+ apply/andP; split; first by done.
+ move: IN IN' => /andP [T1 _] /andP [_ T2].
+ by apply leq_ltn_trans with (job_arrival j).
+ }
+ }
+ subst t1'.
+ have EQ: t2 = t2'.
+ { apply/eqP.
+ apply/negPn/negP; intros CONTR.
+ move: BUSY => [[IN [_ NQ]] QT2].
+ move: BUSY' => [[IN' [_ NQ']] QT2'].
+ move: CONTR; rewrite neq_ltn; move => /orP [LTGT].
+ { apply NQ' with t2; try done; clear NQ'.
+ apply/andP; split; last by done.
+ move: IN IN' => /andP [_ T1] /andP [T2 _].
+ by apply leq_ltn_trans with (job_arrival j).
+ }
+ { apply NQ with t2'; try done; clear NQ.
+ apply/andP; split; last by done.
+ move: IN IN' => /andP [T1 _] /andP [_ T2].
+ by apply leq_ltn_trans with (job_arrival j).
+ }
+ }
+ subst t2'.
+ by done.
+ Qed.
+
+ End BusyInterval.
+
+ (* In this section, we introduce some assumptions about the
+ busy interval that are fundamental for the analysis. *)
+ Section BusyIntervalProperties.
+
+ (* We say that a schedule is "work_conserving" iff for any job j from task tsk and
+ at any time t within a busy interval, there are only two options:
+ either (a) interference(j, t) holds or (b) job j is scheduled at time t. *)
+ Definition work_conserving :=
+ forall j t1 t2 t,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ job_cost j > 0 >
+ busy_interval j t1 t2 >
+ t1 <= t < t2 >
+ ~ interference j t <> job_scheduled_at j t.
+
+ (* Next, we say that busy intervals of task tsk are bounded by L iff, for any job j of task
+ tsk, there exists a busy interval with length at most L. Note that the existence of such a
+ bounded busy interval is not guaranteed if the schedule is overloaded with work.
+ Therefore, in the later concrete analyses, we will have to introduce an additional
+ condition that prevents overload. *)
+ Definition busy_intervals_are_bounded_by L :=
+ forall j,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ job_cost j > 0 >
+ exists t1 t2,
+ t1 <= job_arrival j < t2 /\
+ t2 <= t1 + L /\
+ busy_interval j t1 t2.
+
+ (* Although we have defined the notion of cumulative interference of a job, it is still hard to be
+ used in a responsetime analysis because of the variability of job parameters. To address this
+ issue, we define the notion of an interference bound. Note that according to the definition of
+ a work conserving schedule, interference does _not_ include execution of a job itself. Therefore,
+ an interference bound is not obliged to take into account the execution of this job. We say that
+ the job interference is bounded by an interference_bound_function (IBF) iff for any job j of
+ task tsk the cumulative interference incurred by j in the subinterval [t1, t1 + delta) of busy
+ interval [t1, t2) does not exceed interference_bound_function(tsk, A, delta), where A is a
+ relative arrival time of job j (with respect to time t1).
+ Let's examine this definition in more detail. First, the IBF bounds the interference only
+ within the interval [t1, t1 + delta) (see a.1, a.2 below). Second, the IBF bounds the
+ interference only until the job is completed, after which the function can behave
+ arbitrarily (see b). And finally, the IBF function might depend not only on the length
+ of the interval, but also on the relative arrival time of job j (see c).
+ While (a.1), (a.2) and (b) are useful for discarding excessive cases, (c) adds
+ flexibility to the IBF, which is important, for instance, when analyzing EDF scheduling. *)
+ Definition job_interference_is_bounded_by (interference_bound_function: Task > time > time > time) :=
+ forall t1 t2 delta j,
+ busy_interval j t1 t2 > (* (a.1) *)
+ t1 + delta < t2 > (* (a.2) *)
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ ~~ job_completed_by j (t1 + delta) > (* (b) *)
+ let offset := job_arrival j  t1 in
+ cumul_interference j t1 (t1 + delta) <= interference_bound_function tsk offset delta (* (c) *).
+
+ End BusyIntervalProperties.
+
+ End Definitions.
+
+End AbstractRTADefinitions.
+
+
\ No newline at end of file
diff git a/model/schedule/uni/limited/abstract_RTA/reduction_of_search_space.v b/model/schedule/uni/limited/abstract_RTA/reduction_of_search_space.v
new file mode 100644
index 0000000000000000000000000000000000000000..9ce65a850a25940338453aabb993279dc2a1beed
 /dev/null
+++ b/model/schedule/uni/limited/abstract_RTA/reduction_of_search_space.v
@@ 0,0 +1,172 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job.
+Require Import rt.model.schedule.uni.schedule.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Reduction of the serach space for Abstract RTA *)
+(** In this module, we prove that in order to calculate the worstcase response time
+ it is sufficient to consider only values of A that lie in the search space defined below. *)
+
+Module AbstractRTAReduction.
+
+ Import Epsilon UniprocessorSchedule.
+
+ (* The responsetime analysis we are presenting in this series of documents is based on searching
+ over all possible values of A, the relative arrival time of the job respective to the beginning
+ of the busy interval. However, to obtain a practically useful responsetime bound, we need to
+ constrain the search space of values of A. In this section, we define an approach to
+ reduce the search space. *)
+ Section SearchSpace.
+
+ Context {Task: eqType}.
+
+ (* First, we provide a constructive notion of equivalent functions. *)
+ Section EquivalentFunctions.
+
+ (* Consider an arbitrary type T... *)
+ Context {T: eqType}.
+
+ (* ...and two function from nat to T. *)
+ Variables f1 f2: nat > T.
+
+ (* Let B be an arbitrary constant. *)
+ Variable B: nat.
+
+ (* Then we say that f1 and f2 are equivalent at values less than B iff
+ for any natural number x less than B [f1 x] is equal to [f2 x]. *)
+ Definition are_equivalent_at_values_less_than :=
+ forall x, x < B > f1 x = f2 x.
+
+ (* And vice versa, we say that f1 and f2 are not equivalent at values
+ less than B iff there exists a natural number x less than B such
+ that [f1 x] is not equal to [f2 x]. *)
+ Definition are_not_equivalent_at_values_less_than :=
+ exists x, x < B /\ f1 x <> f2 x.
+
+ End EquivalentFunctions.
+
+ (* Let tsk be any task that is to be analyzed *)
+ Variable tsk: Task.
+
+ (* To ensure that the analysis procedure terminates, we assume an upper bound B on
+ the values of A that must be checked. The existence of B follows from the assumption
+ that the system is not overloaded (i.e., it has bounded utilization). *)
+ Variable B: time.
+
+ (* Instead of searching for the maximum interference of each individual job, we
+ assume a pertask interference bound function [IBF(tsk, A, x)] that is parameterized
+ by the relative arrival time A of a potential job (see abstract_RTA.definitions.v file). *)
+ Variable interference_bound_function: Task > time > time > time.
+
+ (* Recall the definition of ε, which defines the neighborhood of a point in the timeline.
+ Note that epsilon = 1 under discrete time. *)
+ (* To ensure that the search converges more quickly, we only check values of A in the interval
+ [0, B) for which the interference bound function changes, i.e., every point x in which
+ interference_bound_function (A  ε, x) is not equal to interference_bound_function (A, x). *)
+ Definition is_in_search_space A :=
+ A = 0 \/
+ 0 < A < B /\ are_not_equivalent_at_values_less_than
+ (interference_bound_function tsk (A  ε)) (interference_bound_function tsk A) B.
+
+ (* In this section we prove that for every A there exists a smaller A_sp
+ in the search space such that interference_bound_function(A_sp,x) is
+ equal to interference_bound_function(A, x). *)
+ Section ExistenceOfRepresentative.
+
+ (* Let A be any constant less than B. *)
+ Variable A: time.
+ Hypothesis H_A_less_than_B: A < B.
+
+ (* We prove that there exists a constant A_sp such that:
+ (a) A_sp is no greater than A, (b) interference_bound_function(A_sp, x) is
+ equal to interference_bound_function(A, x) and (c) A_sp is in the search space.
+ In other words, either A is already inside the search space, or we can go
+ to the "left" until we reach A_sp, which will be inside the search space. *)
+ Lemma representative_exists:
+ exists A_sp,
+ A_sp <= A /\
+ are_equivalent_at_values_less_than (interference_bound_function tsk A)
+ (interference_bound_function tsk A_sp) B /\
+ is_in_search_space A_sp.
+ Proof.
+ induction A as [n].
+  exists 0; repeat split.
+ by rewrite /is_in_search_space; left.
+  have ALT:
+ all (fun t => interference_bound_function tsk n t == interference_bound_function tsk n.+1 t) (iota 0 B)
+ \/ has (fun t => interference_bound_function tsk n t != interference_bound_function tsk n.+1 t) (iota 0 B).
+ { apply/orP.
+ rewrite [_  _]Bool.negb_involutive Bool.negb_orb.
+ apply/negP; intros CONTR.
+ move: CONTR => /andP [NALL /negP NHAS]; apply: NHAS.
+ by rewrite has_predC /predC in NALL.
+ }
+ feed IHn; first by apply ltn_trans with n.+1.
+ move: IHn => [ASP [NEQ [EQ SP]]].
+ move: ALT => [/allP ALT /hasP ALT].
+ { exists ASP; repeat split; try done.
+ { by apply leq_trans with n. }
+ { intros x LT.
+ move: (ALT x) => T. feed T; first by rewrite mem_iota; apply/andP; split.
+ move: T => /eqP T.
+ by rewrite T EQ.
+ }
+ }
+ { exists n.+1; repeat split; try done.
+ rewrite /is_in_search_space; right.
+ split; first by apply/andP; split.
+ move: ALT => [y IN N].
+ exists y.
+ move: IN; rewrite mem_iota add0n. move => /andP [_ LT].
+ split; first by done.
+ rewrite subn1 pred_Sn.
+ intros CONTR; move: N => /negP N; apply: N.
+ by rewrite CONTR.
+ }
+ Qed.
+
+ End ExistenceOfRepresentative.
+
+ (* In this section we prove that any solution of the responsetime recurrence for
+ a given point A_sp in the search space also gives a solution for any point
+ A that shares the same interference bound. *)
+ Section FixpointSolutionForAnotherA.
+
+ (* Suppose A_sp + F_sp is a "small" solution (i.e. less than B) of the responsetime recurrence. *)
+ Variables A_sp F_sp: time.
+ Hypothesis H_less_than: A_sp + F_sp < B.
+ Hypothesis H_fixpoint: A_sp + F_sp = interference_bound_function tsk A_sp (A_sp + F_sp).
+
+ (* Next, let A be any point such that: (a) A_sp <= A <= A_sp + F_sp and
+ (b) interference_bound_function(A, x) is equal to
+ interference_bound_function(A_sp, x) for all x less than B. *)
+ Variable A: time.
+ Hypothesis H_bounds_for_A: A_sp <= A <= A_sp + F_sp.
+ Hypothesis H_equivalent:
+ are_equivalent_at_values_less_than
+ (interference_bound_function tsk A)
+ (interference_bound_function tsk A_sp) B.
+
+ (* We prove that there exists a consant F such that [A + F] is equal to [A_sp + F_sp]
+ and [A + F] is a solution for the responsetime recurrence for A. *)
+ Lemma solution_for_A_exists:
+ exists F,
+ A_sp + F_sp = A + F /\
+ F <= F_sp /\
+ A + F = interference_bound_function tsk A (A + F).
+ Proof.
+ move: H_bounds_for_A => /andP [NEQ1 NEQ2].
+ set (X := A_sp + F_sp) in *.
+ exists (X  A); split; last split.
+  by rewrite subnKC.
+  by rewrite leq_subLR /X leq_add2r.
+  by rewrite subnKC // H_equivalent.
+ Qed.
+
+ End FixpointSolutionForAnotherA.
+
+ End SearchSpace.
+
+End AbstractRTAReduction.
+
diff git a/model/schedule/uni/limited/abstract_RTA/sufficient_condition_for_lock_in_service.v b/model/schedule/uni/limited/abstract_RTA/sufficient_condition_for_lock_in_service.v
new file mode 100644
index 0000000000000000000000000000000000000000..cd31ebed9c8eef462da2e8398962d3cda441a27c
 /dev/null
+++ b/model/schedule/uni/limited/abstract_RTA/sufficient_condition_for_lock_in_service.v
@@ 0,0 +1,242 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.schedule.
+Require Import rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.abstract_RTA.definitions.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Lockin service of a job *)
+(** In this module, we provide a sufficient condition under which a job
+ receives enough service to become nonpreemptive. *)
+Module AbstractRTALockInService.
+
+ Import Job Epsilon UniprocessorSchedule Service AbstractRTADefinitions.
+
+ (* Previously we defined the notion of lockin service (see limited.schedule.v file).
+ Lockin service is the amount of service after which a job cannot be preempted until
+ its completion. In this section we prove that if cumulative interference inside a
+ busy interval is bounded by a certain constant then a job executes long enough to
+ reach its lockin service and become nonpreemptive. *)
+ Section LockInService.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent arrivals... *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence. *)
+ Variable sched: schedule Job.
+
+ (* Assume that the job costs are no larger than the task costs. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Let tsk be any task that is to be analyzed. *)
+ Variable tsk: Task.
+
+ (* Assume we are provided with abstract functions for interference and interfering workload. *)
+ Variable interference: Job > time > bool.
+ Variable interfering_workload: Job > time > time.
+
+ (* For simplicity, let's define some local names. *)
+ Let work_conserving := work_conserving job_arrival job_cost job_task arr_seq sched tsk.
+ Let cumul_interference := cumul_interference interference.
+ Let cumul_interfering_workload := cumul_interfering_workload interfering_workload.
+ Let busy_interval := busy_interval job_arrival job_cost sched interference interfering_workload.
+
+ (* We assume that the schedule is workconserving. *)
+ Hypothesis H_work_conserving: work_conserving interference interfering_workload.
+
+ (* Let j be any job of task tsk with positive job cost. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Next, consider any busy interval [t1, t2) of job j. *)
+ Variable t1 t2: time.
+ Hypothesis H_busy_interval: busy_interval j t1 t2.
+
+ (* First, we prove that job j completes by the end of the busy interval.
+ Note that the busy interval contains the execution of job j, in addition
+ time instant t2 is a quiet time. Thus by the definition of a quiet time
+ the job should be completed before time t2. *)
+ Lemma job_completes_within_busy_interval:
+ completed_by job_cost sched j t2.
+ Proof.
+ move: (H_busy_interval) => [[/andP [_ LT] [_ _]] [_ QT2]].
+ unfold pending, has_arrived in QT2.
+ move: QT2; rewrite /pending negb_and; move => /orP [QT2QT2].
+ { by move: QT2 => /negP QT2; exfalso; apply QT2, ltnW. }
+ by rewrite Bool.negb_involutive in QT2.
+ Qed.
+
+ (* In this section we show that the cumulative interference is a complement to
+ the total time where job j is scheduled inside the busy interval. *)
+ Section InterferenceIsComplement.
+
+ (* Consider any subinterval [t, t + delta) inside the busy interval [t1, t2). *)
+ Variable t delta: time.
+ Hypothesis H_greater_than_or_equal: t1 <= t.
+ Hypothesis H_less_or_equal: t + delta <= t2.
+
+ (* We prove that sum of cumulative service and cumulative interference
+ in the interval [t, t + delta) is equal to delta. *)
+ Lemma interference_is_complement_to_schedule:
+ service_during sched j t (t + delta) + cumul_interference j t (t + delta) = delta.
+ Proof.
+ rewrite /service_during /cumul_interference.
+ rewrite big_split //=.
+ rewrite {2}(sum_of_ones t delta).
+ apply/eqP; rewrite eqn_leq; apply/andP; split.
+  rewrite [X in X <= _]big_nat_cond [X in _ <= X]big_nat_cond.
+ apply leq_sum; move => x /andP [/andP [GE2 LT2] _ ].
+ case IJX: (interference j x); last by rewrite addn0 /service_at; case scheduled_at.
+ rewrite addn1 ltnNge; apply/negP; intros CONTR.
+ specialize (H_work_conserving j t1 t2 x).
+ feed_n 5 H_work_conserving; try done.
+ { apply/andP; split.
+ apply leq_trans with t; try done.
+ apply leq_trans with (t + delta); try done.
+ }
+ move: H_work_conserving => [H1 H2].
+ feed H2. rewrite lt0b in CONTR. by done.
+ by rewrite IJX in H2.
+  rewrite [X in X <= _]big_nat_cond [X in _ <= X]big_nat_cond.
+ apply leq_sum; move => x /andP [/andP [GE2 LT2] _ ].
+ case IJX: (interference j x); first by rewrite addn1.
+ rewrite addn0.
+ specialize (H_work_conserving j t1 t2 x); feed_n 5 H_work_conserving; try done.
+ { apply/andP; split.
+ apply leq_trans with t; try done.
+ apply leq_trans with (t + delta); try done. }
+ move: H_work_conserving => [H1 H2].
+ feed H1; first by rewrite IJX.
+ by rewrite lt0b.
+ Qed.
+
+ End InterferenceIsComplement.
+
+ (* In this section, we prove a sufficient condition under which job j receives enough service. *)
+ Section InterferenceBoundedImpliesEnoughService.
+
+ (* Let progress_of_job be the desired service of job j. *)
+ Variable progress_of_job: time.
+ Hypothesis H_progress_le_job_cost: progress_of_job <= job_cost j.
+
+ (* Assume that for some delta, the sum of desired progress and cumulative
+ interference is bounded by delta (i.e., the supply). *)
+ Variable delta: time.
+ Hypothesis H_total_workload_is_bounded:
+ progress_of_job + cumul_interference j t1 (t1 + delta) <= delta.
+
+ (* Then, it must be the case that the job has received no less service than progress_of_job. *)
+ Theorem j_receives_at_least_lock_in_service:
+ service sched j (t1 + delta) >= progress_of_job.
+ Proof.
+ case NEQ: (t1 + delta <= t2); last first.
+ { intros.
+ have L8 := job_completes_within_busy_interval.
+ apply leq_trans with (job_cost j); first by done.
+ rewrite /service.
+ rewrite (service_during_cat _ _ t2).
+ apply leq_trans with (service_during sched j 0 t2); [by done  by rewrite leq_addr].
+ by apply/andP; split; last (apply negbT in NEQ; apply ltnW; rewrite ltnNge).
+ }
+ { move: H_total_workload_is_bounded => BOUND.
+ apply subh3 in BOUND.
+ apply leq_trans with (delta  cumul_interference j t1 (t1 + delta)); first by done.
+ apply leq_trans with (service_during sched j t1 (t1 + delta)).
+ { rewrite {1}[delta](interference_is_complement_to_schedule t1) //.
+ rewrite addnBA // subnn addn0 //.
+ }
+ { unfold service.
+ rewrite [X in _ <= X](service_during_cat _ _ t1).
+ rewrite leq_addl //.
+ by apply/andP; split; last rewrite leq_addr.
+ }
+ }
+ Qed.
+
+ End InterferenceBoundedImpliesEnoughService.
+
+ (* In this section we prove a simple lemma about completion of
+ a job after is reaches lockin service. *)
+ Section CompletionOfJobAfterLockInService.
+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs_dont_execute:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* Consider a proper job lockin service function, i.e... *)
+ Variable job_lock_in_service: Job > time.
+
+ (* ...(1) for any job j the lockin service of job j is positive... *)
+ Hypothesis H_lock_in_service_positive:
+ job_lock_in_service_positive job_cost arr_seq job_lock_in_service.
+
+ (* ...(2) it also lessthanorequal to the job_cost... *)
+ Hypothesis H_lock_in_service_le_job_cost:
+ job_lock_in_service_le_job_cost job_cost arr_seq job_lock_in_service.
+
+ (* ..., and (3) we assume that the scheduler respects the notion of the lockin service. *)
+ Hypothesis H_job_nonpreemptive_after_lock_in_service:
+ job_nonpreemptive_after_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* Then, job j must complete in [job_cost j  job_lock_in_service j] time
+ units after it reaches lockin service. *)
+ Lemma job_completes_after_reaching_lock_in_service:
+ forall t,
+ job_lock_in_service j <= service sched j t >
+ completed_by job_cost sched j (t + (job_cost j  job_lock_in_service j)).
+ Proof.
+ move => t ES.
+ set (job_cost j  job_lock_in_service j) as job_last.
+ move: (H_job_nonpreemptive_after_lock_in_service j t) => LSNP.
+ apply negbNE; apply/negP; intros CONTR.
+ have SCHED: forall t', t <= t' <= t + job_last > scheduled_at sched j t'.
+ { move => t' /andP [GE LT].
+ rewrite [t'](@subnKC t) //.
+ apply LSNP; [ by apply H_j_arrives  by rewrite leq_addr  by done  ].
+ rewrite subnKC //.
+ apply/negP; intros COMPL.
+ move: CONTR => /negP Temp; apply: Temp.
+ apply completion_monotonic with (t0 := t'); try done.
+ }
+ have SERV: job_last + 1 <= \sum_(t <= t' < t + (job_last + 1)) service_at sched j t'.
+ { rewrite {1}[job_last + 1]addn0 {2}(subnn t) addnBA // addnC.
+ rewrite {1}[_+__]addn0 [_+__]mul1n iter_addn big_const_nat.
+ rewrite big_nat_cond [in X in _ <= X]big_nat_cond.
+ rewrite leq_sum //.
+ move => t' /andP [NEQ _].
+ rewrite /service_at lt0b.
+ apply SCHED.
+ by rewrite addn1 addnS ltnS in NEQ.
+ }
+ move: (H_completed_jobs_dont_execute j (t + job_last.+1)).
+ rewrite /completed_jobs_dont_execute.
+ rewrite leqNgt; move => /negP T; apply: T.
+ rewrite /service (service_during_cat _ _ t); last by (apply/andP; split; last rewrite leq_addr).
+ apply leq_trans with (
+ job_lock_in_service j + service_during sched j t (t + job_last.+1));
+ last by rewrite leq_add2r.
+ apply leq_trans with (job_lock_in_service j + job_last.+1); last by rewrite leq_add2l /service_during addn1.
+ by rewrite addnS ltnS subnKC; eauto 2.
+ Qed.
+
+ End CompletionOfJobAfterLockInService.
+
+ End LockInService.
+
+End AbstractRTALockInService.
+
diff git a/model/schedule/uni/limited/busy_interval.v b/model/schedule/uni/limited/busy_interval.v
new file mode 100644
index 0000000000000000000000000000000000000000..9f31e9cbdc5542ce1ce3b14920bfbb72983e18b9
 /dev/null
+++ b/model/schedule/uni/limited/busy_interval.v
@@ 0,0 +1,1012 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.task
+ rt.model.arrival.basic.job
+ rt.model.arrival.basic.arrival_sequence
+ rt.model.priority
+ rt.model.arrival.basic.task_arrival.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule.
+Require Import rt.model.schedule.uni.limited.platform.definitions.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(** * Busy Interval for JLFPmodels *)
+(** In this module we define the notion of busy intervals for uniprocessor for JLFP schedulers. *)
+Module BusyIntervalJLFP.
+
+ Import Job Priority UniprocessorSchedule LimitedPreemptionPlatform Service Workload TaskArrival.
+
+ Section Definitions.
+
+ Context {Task: eqType}.
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent arrival times... *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+
+ (* ...and any uniprocessor schedule of these jobs. *)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence:
+ jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* 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 job_arrival job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_remaining_cost j t := remaining_cost job_cost sched j t.
+
+ (* In this section, we define the notion of a busy interval. *)
+ Section BusyInterval.
+
+ (* 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_task j = tsk.
+
+ (* We say that t is a quiet time for j iff every higherpriority job from
+ the arrival sequence that arrived before t has completed by that time. *)
+ Definition quiet_time (t: time) :=
+ forall j_hp,
+ arrives_in arr_seq j_hp >
+ higher_eq_priority j_hp j >
+ arrived_before job_arrival j_hp t >
+ job_completed_by j_hp t.
+
+ (* Based on the definition of quiet time, we say that interval
+ [t1, t_busy) is a (potentially unbounded) busyinterval prefix
+ iff the interval starts with a quiet time where a higher or equal
+ priority job is released and remains nonquiet. We also require
+ job j to be release in the interval. *)
+ Definition busy_interval_prefix (t1 t_busy: time) :=
+ 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 busyinterval prefix and t2 is a quiet time. *)
+ Definition busy_interval (t1 t2: time) :=
+ busy_interval_prefix t1 t2 /\
+ quiet_time t2.
+
+ End BusyInterval.
+
+ (* 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_task j = tsk.
+
+ (* 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 workconserving in
+ the sense of the definition given in rt.model.schedule.uni.basic.platform. Therefore, it
+ cannot be applied to models with jitter or selfsuspensions. *)
+ Definition is_priority_inversion t :=
+ 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 :=
+ \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: time) :=
+ forall (t1 t2: time),
+ busy_interval_prefix 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: time) :=
+ 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.
+
+ (* Now we prove some lemmas about busy intervals. *)
+ Section Lemmas.
+
+ (* 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_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Recall the list of jobs that arrive in any interval. *)
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let quiet_time t1 := quiet_time j t1.
+ Let busy_interval_prefix t1 t2 := busy_interval_prefix j t1 t2.
+ Let busy_interval t1 t2 := busy_interval j t1 t2.
+ Let is_priority_inversion_bounded_by K := priority_inversion_of_job_is_bounded_by 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: FP_is_reflexive higher_eq_priority.
+
+ (* Consider any busy interval [t1, t2) of job j. *)
+ Variable t1 t2: time.
+ 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].
+ by apply QUIET.
+ Qed.
+
+ End BasicLemma.
+
+ (* In this section, we prove that during a busy interval there
+ always exists a pending job. *)
+ Section ExistsPendingJob.
+
+ (* Assume that jobs do not execute after completion. *)
+ Hypothesis H_completed_jobs_dont_execute:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* Let [t1, t2] be any interval where time t1 is quiet and time t2 is not quiet. *)
+ Variable t1 t2: time.
+ 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 job_arrival 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 with (job_arrival0 := job_arrival) 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 workconserving and that jobs do
+ not execute before their arrival nor after completion. *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+
+ (* Next, we assume that the priority relation is reflexive and transitive. *)
+ Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.
+
+ (* Consider any busy interval prefix [t1, t2). *)
+ Variable t1 t2: time.
+ 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,
+ 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; first (apply/andP; split).
+  by done.
+  apply/negP; intros COMP.
+ move: NCOMP => /negP NCOMP; apply: NCOMP.
+ by apply completion_monotonic with t.
+  move: IDLE => /eqP IDLE.
+ by rewrite /scheduled_at IDLE.
+ }
+ move: IDLE WC => /eqP IDLE [jo /eqP SCHED].
+ by rewrite 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 higherorequal
+ 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: (ltngtP t1.+1 t2) => [GTCONTREQ].
+ { move: (H_busy_interval_prefix) => [_ [QT [NQT _]]].
+ have EX:
+ exists (hps: seq Job),
+ forall jhp,
+ jhp \in hps <> arrives_in arr_seq jhp /\ job_pending_at jhp t
+ /\ higher_eq_priority jhp j.
+ { exists (filter
+ (fun jo => (job_pending_at jo t) && (higher_eq_priority jo j))
+ (jobs_arrived_between arr_seq 0 t.+1)).
+ intros; split; intros.
+ { move: H; rewrite mem_filter; move => /andP [/andP [PEN HP] IN].
+ repeat split; try done.
+ by eapply in_arrivals_implies_arrived; eauto 2.
+ }
+ { move: H => [ARR [PEN HP]].
+ rewrite mem_filter.
+ apply/andP; split; first (apply/andP; split); try done.
+ apply arrived_between_implies_in_arrivals with (job_arrival0 := job_arrival); try done.
+ apply/andP; split; first by done.
+ rewrite ltnS.
+ by move: PEN => /andP [T _].
+ }
+ }
+ move: EX => [hps SE].
+ case FL: (hps) => [  jhp jhps].
+ { subst hps.
+ 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].
+ feed SE2. 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.
+ by done.
+ }
+ { apply NQT with t; first by apply/andP; split.
+ intros jhp ARR HP ARRB.
+ apply negbNE; apply/negP; intros NCOMP.
+ move: (SE jhp) => [_ SE2].
+ feed SE2. repeat split; try done.
+  by apply/andP; split; first apply ltnW.
+ by done.
+ }
+ }
+ { exists jhp.
+ specialize (SE jhp).
+ move: SE => [SE1 _].
+ feed SE1; first by rewrite FL in_cons; apply/orP; left.
+ by done.
+ }
+ }
+ { exfalso.
+ rewrite ltnS in CONTR.
+ move: (leq_ltn_trans GE LT) => NEQ.
+ by move: CONTR; rewrite leqNgt; move => /negP CONTR; apply: CONTR.
+ }
+ { subst t2; rewrite ltnS in LT.
+ have EQ: t1 = t; first by apply/eqP; rewrite eqn_leq; apply/andP; split.
+ subst t1; clear GE LT.
+ move: (H_busy_interval_prefix) => [_ [QTt [_ REL]]].
+ exists j; repeat split.
+  by done.
+  move: REL; rewrite ltnS eqn_leq eq_sym; move => /eqP REL.
+ rewrite REL.
+ by eapply UniprocessorSchedule.job_pending_at_arrival; eauto 2.
+  by apply H_priority_is_reflexive.
+ }
+ 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, platform.Platform.work_conserving in *.
+ feed (H_work_conserving _ t ARR).
+ apply/andP; split; first by done.
+ move: IDLE => /eqP IDLE. unfold scheduled_at. rewrite IDLE. by done.
+ move: (H_work_conserving) => [jo SCHED].
+ move: IDLE SCHED => /eqP IDLE /eqP SCHED.
+ by rewrite SCHED in IDLE.
+ Qed.
+
+ End ProcessorAlwaysBusy.
+
+ (* In section we prove a few auxiliary lemmas about quiet time and service. *)
+ Section QuietTimeAndServiceOfJobs.
+
+ (* Assume that there are no duplicate job arrivals... *)
+ Hypothesis H_arrival_sequence_is_a_set:
+ arrival_sequence_is_a_set arr_seq.
+
+ (* ...and that jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* We also assume that the schedule is workconserving. *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* Let t1 be a quiet time. *)
+ Variable t1: time.
+ Hypothesis H_quiet_time: quiet_time t1.
+
+ (* We prove that jobs with higherthanorequal priority that
+ arrived before time instant t1 receive no service after
+ time instant t1. *)
+ Lemma jobs_receive_no_service_after_quiet_time:
+ forall (Δ: time),
+ let arrivals_after_t1 := arrivals_between t1 (t1 + Δ) in
+ let all_arrivals := arrivals_between 0 (t1 + Δ) in
+
+ \sum_(j_hp < arrivals_after_t1  higher_eq_priority j_hp j)
+ service_during sched j_hp t1 (t1 + Δ) =
+ \sum_(j_hp < all_arrivals  higher_eq_priority j_hp j)
+ service_during sched j_hp t1 (t1 + Δ).
+ Proof.
+ intros.
+ rewrite /arrivals_after_t1 /all_arrivals /arrivals_between.
+ rewrite [in X in _ = X](job_arrived_between_cat _ _ t1);
+ [   rewrite leq_addr]; try done.
+ rewrite big_cat //=.
+ rewrite {1}[\sum_(j < jobs_arrived_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.
+ eapply completed_implies_not_scheduled with job_cost; first by done.
+ 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.
+
+ (* Assume that there is no quiet time in the interval (t1, t1 + Δ]. *)
+ Variable Δ: time.
+ Hypothesis H_no_quiet_time: forall t, t1 < t <= t1 + Δ > ~ quiet_time t.
+
+ (* Next we prove that the total service within a "nonquiet"
+ time interval (t1, t1 + Δ] is exactly Δ. *)
+ Lemma no_idle_time_within_non_quiet_time_interval:
+ \sum_(j < arrivals_between 0 (t1 + Δ)) service_during sched j t1 (t1 + Δ) = Δ.
+ Proof.
+ intros.
+ have EQ: \sum_(t1 <= x < t1 + Δ) 1 = Δ.
+ { by rewrite big_const_nat iter_addn mul1n addn0 {2}[t1]addn0 subnDl subn0. }
+ rewrite {3}EQ exchange_big //=. clear EQ.
+ apply/eqP; rewrite eqn_leq; apply/andP; split.
+ { rewrite leq_sum //.
+ move => t' _.
+ case SCHED: (sched t') => [j1  ]; simpl.
+ { case ARR: (j1 \in arrivals_between 0 (t1 + Δ)).
+ { rewrite (big_rem j1) //=; simpl.
+ rewrite /service_at /scheduled_at SCHED; simpl.
+ rewrite [1]addn0 leq_add //.
+  by case (Some j1 == Some j1).
+  rewrite leqn0 big1_seq; first by done.
+ move => j2 /andP [_ ARRj2].
+ apply/eqP; rewrite eqb0.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; subst j2; clear CONTR.
+ rewrite rem_filter in ARRj2; last first.
+ eapply arrivals_uniq; eauto 2.
+ move: ARRj2; rewrite mem_filter; move => /andP [/negP CONTR _].
+ by apply: CONTR. }
+ { apply leq_trans with 0; last by done.
+ rewrite leqn0 big1_seq; first by done.
+ move => j2 /andP [_ ARRj2].
+ apply/eqP; rewrite eqb0.
+ rewrite /scheduled_at SCHED.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; clear CONTR.
+ by subst j2; rewrite ARR in ARRj2. } }
+ { apply leq_trans with 0; last by done.
+ rewrite leqn0 big1_seq; first by done.
+ move => j2 /andP [_ ARRj2].
+ by rewrite /service_at /scheduled_at SCHED. }
+ }
+ { 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.
+ case SCHED: (sched t') => [j1  ]; last first.
+ { exfalso.
+ move: LT; rewrite leq_eqVlt; move => /orP [/eqP EQLT].
+ { subst t'.
+ feed (H_no_quiet_time t1.+1); first by apply/andP; split.
+ move: SCHED => /eqP SCHED.
+ apply: H_no_quiet_time.
+ by apply idle_time_implies_quiet_time_at_the_next_time_instant.
+ }
+ { feed (H_no_quiet_time t'). 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 move: SCHEDhp => /eqP SCHEDhp; rewrite SCHED 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 /eqP SCHEDother].
+ by rewrite SCHED in SCHEDother.
+ }
+ }
+ { exists j1; split.
+  unfold arrivals_between.
+ apply arrived_between_implies_in_arrivals with job_arrival; try done.
+ unfold jobs_come_from_arrival_sequence in *.
+ apply H_jobs_come_from_arrival_sequence with t'.
+ unfold scheduled_at . rewrite SCHED. by done.
+ unfold arrived_between; apply/andP; split; first by done.
+ unfold jobs_must_arrive_to_execute in *.
+ move: SCHED => /eqP SCHED.
+ apply H_jobs_must_arrive_to_execute in SCHED.
+ unfold has_arrived in SCHED.
+ by apply leq_ltn_trans with t'.
+ 
+ by rewrite /service_at /scheduled_at SCHED lt0b. }
+ }
+ 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 there are no duplicate job arrivals... *)
+ Hypothesis H_arrival_sequence_is_a_set:
+ arrival_sequence_is_a_set arr_seq.
+
+ (* ...and that jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Also assume a workconserving JLFP schedule, ... *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* ...in which the priority relation is reflexive and transitive. *)
+ Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.
+
+
+ (* Next, we recall the notion of workload of all jobs released in a given interval
+ [t1, t2) that have higherorequal priority w.r.t the job j being analyzed. *)
+ Let hp_workload t1 t2 :=
+ workload_of_higher_or_equal_priority_jobs
+ job_cost (arrivals_between t1 t2) higher_eq_priority j.
+
+ (* With regard to the jobs with higherorequal 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 (arrivals_between t1 t2) higher_eq_priority 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: time.
+ 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.
+ move: (H_from_arrival_sequence) => FROM.
+ rename H_j_is_pending into PEND,
+ H_work_conserving into WORK, H_priority_is_reflexive into REFL.
+ unfold busy_interval_prefix.
+ set dec_quiet :=
+ fun t => all (fun j_hp =>
+ higher_eq_priority j_hp j ==> (completed_by job_cost sched j_hp t))
+ (jobs_arrived_before arr_seq t).
+ destruct ([exists t:'I_t_busy.+1, dec_quiet t]) eqn:EX.
+ {
+ set last := \max_(t < t_busy.+1  dec_quiet t) t.
+ move: EX => /existsP [t EX].
+ have PRED: dec_quiet last by apply (bigmax_pred t_busy.+1 dec_quiet t).
+ have QUIET: quiet_time last.
+ {
+ move: PRED => /allP PRED.
+ intros j_hp IN HP ARR.
+ feed (PRED j_hp).
+ by apply arrived_between_implies_in_arrivals with (job_arrival0 := job_arrival).
+ by rewrite HP implyTb in PRED.
+ }
+ exists last.
+ have JAIN: last <= job_arrival j <= t_busy.
+ {
+ apply/andP; split; last by move: PEND => /andP [ARR _].
+ apply contraT; rewrite ltnNge; intros BEFORE.
+ feed (QUIET j FROM); first by apply REFL.
+ specialize (QUIET BEFORE).
+ move: PEND => /andP [_ NOTCOMP].
+ apply completion_monotonic with (t' := t_busy) in QUIET;
+ [by rewrite QUIET in NOTCOMP ].
+ by apply bigmax_ltn_ord with (i0 := t).
+ }
+ split; last by done.
+ repeat split.
+  by apply bigmax_ltn_ord with (i0 := t).
+  by done.
+ 
+ move => t0 /andP [GTlast LTbusy] QUIET0.
+ have PRED0: dec_quiet t0.
+ {
+ apply/allP; intros j_hp ARR; apply/implyP; intros HP.
+ apply QUIET0.
+  by eapply in_arrivals_implies_arrived; eauto.
+  by done.
+  by eapply in_arrivals_implies_arrived_before; eauto.
+ }
+ have BUG: t0 <= last.
+ {
+ have LE := @leq_bigmax_cond _ (fun (x: 'I_t_busy.+1) => dec_quiet x)
+ (fun x => x) (Ordinal LTbusy) PRED0.
+ by apply LE.
+ }
+ apply leq_trans with (p := last) in GTlast; last by done.
+ by rewrite ltnn in GTlast.
+  by rewrite ltnS.
+ }
+ {
+ 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 _].
+ split. by done.
+ split; first by intros j_hp _ _ ARR; rewrite /arrived_before ltn0 in ARR.
+ split.
+ 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.
+  by eapply in_arrivals_implies_arrived; eauto.
+  by done.
+  by eapply in_arrivals_implies_arrived_before; eauto.
+ 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 upperbounded by the supply, then the busy interval eventually ends. *)
+ Section UpperBound.
+
+ (* Consider any busy interval prefix of job j. *)
+ Variable t1: time.
+ 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: time.
+ 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: time.
+ 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 nonquiet, the processor is always busy
+ with tasks of higherorequal 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 j t1 (t1 + delta) + hp_service t1 (t1 + delta)); last first.
+ { rewrite leq_add2r.
+ destruct (t1 + delta <= t_busy.+1) eqn:NEQ.
+ { apply H_priority_inversion_is_bounded in H_is_busy_prefix.
+ apply leq_trans with (cumulative_priority_inversion j t1 t_busy.+1); last by done.
+ unfold cumulative_priority_inversion.
+ rewrite [X in _ <= X](@big_cat_nat _ _ _ (t1 + delta)) //=.
+ rewrite leq_addr //.
+ by rewrite leq_addr.
+ }
+ { apply H_priority_inversion_is_bounded.
+ apply negbT in NEQ. rewrite ltnNge in NEQ.
+ 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].
+ apply/andP; split; first by done.
+ by apply ltn_trans with (t_busy.+1).
+ }
+ }
+ unfold hp_service, service_of_higher_or_equal_priority_jobs, service_of_jobs.
+ rewrite jobs_receive_no_service_after_quiet_time //.
+ rewrite sum_pred_diff.
+ rewrite addnBA; last first.
+ { rewrite big_mkcond //= leq_sum //.
+ by intros j' _; case (higher_eq_priority j' j). }
+ rewrite addnC.
+ rewrite addnBA; last first.
+ rewrite exchange_big //=.
+ unfold cumulative_priority_inversion.
+ unfold is_priority_inversion.
+ apply leq_sum_seq.
+ move => t II _.
+ rewrite mem_index_iota in II; move: II => /andP [GEi LEt].
+ rewrite big_mkcond //=.
+ case SCHED: (sched t) => [j1  ]; simpl.
+ { case PRIO1: (higher_eq_priority j1 j); simpl.
+ { rewrite leqn0 big1_seq; first by done.
+ move => j2 /andP [_ ARRj2].
+ case PRIO2: (higher_eq_priority j2 j); simpl; first by done.
+ rewrite /service_at /scheduled_at SCHED.
+ case EQ: (j1 == j2).
+ { move: EQ => /eqP EQ; subst j2.
+ by rewrite PRIO1 in PRIO2. }
+ { apply/eqP; rewrite eqb0.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; clear CONTR.
+ by subst j2; rewrite PRIO1 in PRIO2. } }
+ { case ARR: (j1 \in arrivals_between 0 (t1 + delta)).
+ { rewrite (big_rem j1) //= PRIO1; simpl.
+ rewrite /service_at /scheduled_at SCHED; simpl.
+ rewrite [1]addn0 leq_add //.
+  by case (Some j1 == Some j1).
+  rewrite leqn0 big1_seq; first by done.
+ move => j2 /andP [_ ARRj2].
+ case (higher_eq_priority j2 j); simpl; first by done.
+ apply/eqP; rewrite eqb0.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; subst j2; clear CONTR.
+ rewrite rem_filter in ARRj2; last first.
+ eapply arrivals_uniq; eauto 2.
+ move: ARRj2; rewrite mem_filter; move => /andP [/negP CONTR _].
+ by apply: CONTR. }
+ { apply leq_trans with 0; last by done.
+ rewrite leqn0 big1_seq; first by done.
+ move => j2 /andP [_ ARRj2].
+ case (higher_eq_priority j2 j); simpl; first by done.
+ apply/eqP; rewrite eqb0.
+ rewrite /scheduled_at SCHED.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; clear CONTR.
+ by subst j2; rewrite ARR in ARRj2. } } }
+ { simpl.
+ rewrite leqn0 big1_seq; first by done.
+ move => j1 /andP [_ ARRj1].
+ rewrite /service_at /scheduled_at SCHED.
+ by case (higher_eq_priority j1 j).
+ }
+ by rewrite no_idle_time_within_non_quiet_time_interval // leq_addr.
+ 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 := jobs_arrived_between arr_seq 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.
+ }
+
+
+ unfold service_during.
+ rewrite (ignore_service_before_arrival job_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.
+ have TOOMUCH := busy_interval_workload_larger_than_interval.
+ have BOUNDED := H_workload_is_bounded.
+ rename H_is_busy_prefix into PREFIX.
+ set dec_quiet :=
+ fun t =>
+ all (fun j_hp => higher_eq_priority j_hp j ==> (completed_by job_cost sched j_hp t))
+ (jobs_arrived_before arr_seq t).
+ destruct ([exists t2:'I_(t1 + delta).+1, (t2 > t1) && dec_quiet t2]) eqn:EX.
+ {
+ have EX': exists (t2: nat), ((t1 < t2 <= t1 + delta) && dec_quiet t2).
+ {
+ move: EX => /existsP [t2 /andP [LE QUIET]].
+ exists t2; apply/andP; split; last by done.
+ by apply/andP; split; last by rewrite ltnS; apply ltn_ord.
+ }
+ have MIN := ex_minnP EX'.
+ move: MIN => [t2 /andP [/andP [GT LE] QUIET] MIN]; clear EX EX'.
+ exists t2; split; first by done.
+ split; last first.
+ {
+ intros j_hp IN HP ARR.
+ move: QUIET => /allP QUIET.
+ feed (QUIET j_hp);
+ first by eapply arrived_between_implies_in_arrivals; last by apply ARR.
+ by move: QUIET => /implyP QUIET; apply QUIET.
+ }
+ split; first by done.
+ split; first by move: PREFIX => [_ [QUIET1 _]].
+ split.
+ move => t /andP [GT1 LT2] BUG.
+ feed (MIN t).
+ {
+ apply/andP; split;
+ first by apply/andP; split;
+ last by apply leq_trans with (n := t2); [by apply ltnW ].
+ apply/allP; intros j_hp ARR; apply/implyP; intro HP.
+ apply BUG.
+  by eapply in_arrivals_implies_arrived, ARR.
+  by done.
+  by eapply in_arrivals_implies_arrived_before, ARR.
+ }
+ by apply leq_ltn_trans with (p := t2) in MIN; first by rewrite ltnn in MIN.
+ {
+ move: PREFIX => [LT [QT [NQ IN]]].
+ have NEQ: t_busy < t2.
+ {
+ rewrite ltnNge; apply/negP; intros CONTR.
+ feed (NQ t2); first by apply/andP; split; last rewrite ltnS.
+ apply NQ.
+ unfold dec_quiet in *.
+ 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.
+ }
+ move: IN => /andP [IN1 IN2].
+ apply/andP; split; first by done.
+ apply leq_ltn_trans with t_busy.
+ rewrite ltnS; by done.
+ by done.
+ }
+ }
+ {
+ 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.
+  by eapply in_arrivals_implies_arrived, ARR.
+  by done.
+  by eapply in_arrivals_implies_arrived_before, ARR.
+ } exfalso; clear ALL'.
+ specialize (TOOMUCH ALL).
+ by have BUG := leq_trans TOOMUCH BOUNDED;
+ rewrite ltnn in BUG.
+ }
+ 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: time.
+ 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: time.
+ 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 /service_during.
+ rewrite (ignore_service_before_arrival job_arrival) //.
+ 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 _ priority_inversion_bound _ delta .
+ feed_n 4 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 responsetime bound. *)
+ Section ResponseTimeBoundFromBusyInterval.
+
+ (* Let priority_inversion_bound be a constant that bounds the length of a priority inversion. *)
+ Variable priority_inversion_bound: time.
+ 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: time.
+ 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 j)) => [ZEROPOS].
+ { 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 Lemmas.
+
+ End Definitions.
+
+End BusyIntervalJLFP.
+
\ No newline at end of file
diff git a/model/schedule/uni/limited/edf/nonpr_reg/concrete_models/response_time_bound.v b/model/schedule/uni/limited/edf/nonpr_reg/concrete_models/response_time_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..418cba723d5ba895823634cba3f546ce1ecca9c0
 /dev/null
+++ b/model/schedule/uni/limited/edf/nonpr_reg/concrete_models/response_time_bound.v
@@ 0,0 +1,640 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time.
+Require Import rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.edf.response_time_bound
+ rt.model.schedule.uni.limited.edf.nonpr_reg.response_time_bound
+ rt.model.schedule.uni.limited.rbf.
+Require Import rt.model.arrival.curves.bounds
+ rt.analysis.uni.arrival_curves.workload_bound.
+Require Import rt.model.schedule.uni.nonpreemptive.schedule
+ rt.model.schedule.uni.limited.platform.limited
+ rt.model.schedule.uni.limited.platform.preemptive
+ rt.model.schedule.uni.limited.platform.nonpreemptive.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * RTA for concrete models *)
+(** In this module we prove the RTA theorems for (1) fully preemptive EDF model,
+ (2) fully nonpreemptive EDF model, (3) EDF with fixed premption points, and
+ (4) EDF with floating nonpreemptive regions. *)
+Module RTAforConcreteModels.
+
+ Import Epsilon Job ArrivalCurves TaskArrival Priority UniprocessorSchedule Workload Service
+ ResponseTime MaxArrivalsWorkloadBound LimitedPreemptionPlatform ModelWithLimitedPreemptions
+ RTAforEDFwithBoundedNonpreemptiveSegmentsWithArrivalCurves NonpreemptiveSchedule
+ FullyNonPreemptivePlatform FullyPreemptivePlatform AbstractRTAforEDFwithArrivalCurves.
+
+ Section Analysis.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+ Variable task_deadline: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* For clarity, let's denote the relative deadline of a task as D. *)
+ Let D tsk := task_deadline tsk.
+
+ (* The relative deadline of a job is equal to the deadline of the corresponding task. *)
+ Let job_relative_deadline j := D (job_task j).
+
+ (* Consider the EDF policy that indicates a higherorequal priority relation. *)
+ Let higher_eq_priority: JLFP_policy Job := EDF job_arrival job_relative_deadline.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Consider an arbitrary task set ts. *)
+ Variable ts: list Task.
+
+ (* Assume that all jobs come from the task set... *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* ...and the cost of a job cannot be larger than the task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Next, consider any uniprocessor schedule... *)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Assume we have sequential jobs, i.e, jobs from the same
+ task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Next, we assume that the schedule is a workconserving schedule. *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* Let's define some local names for clarity. *)
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+ Let task_rbf_changes_at A := task_rbf_changes_at task_cost max_arrivals tsk A.
+ Let bound_on_total_hep_workload_changes_at :=
+ bound_on_total_hep_workload_changes_at task_cost task_deadline ts max_arrivals tsk.
+
+ (* We introduce the abbreviation "rbf" for the task request bound function,
+ which is defined as [task_cost(T) × max_arrivals(T,Δ)] for a task T. *)
+ Let rbf := task_request_bound_function task_cost max_arrivals.
+
+ (* Next, we introduce task_rbf as an abbreviation
+ for the task request bound function of task tsk. *)
+ Let task_rbf := rbf tsk.
+
+ (* Using the sum of individual request bound functions, we define the request bound
+ function of all tasks (total request bound function). *)
+ Let total_rbf := total_request_bound_function task_cost max_arrivals ts.
+
+ (* Next, we define an upper bound on interfering workload received from jobs
+ of other tasks with higherthanorequal priority. *)
+ Let bound_on_total_hep_workload A Δ :=
+ \sum_(tsk_o < ts  tsk_o != tsk)
+ rbf tsk_o (minn ((A + ε) + D tsk  D tsk_o) Δ).
+
+ (** * RTA for fully preemptive EDF model *)
+ (** In this section we prove the RTA theorem for the fully preemptive EDF model *)
+ Section RTAforFullyPreemptiveEDFModelwithArrivalCurves.
+
+ (* First, we assume that the schedule respects the JLFP policy
+ under a model with fixed preemption points. *)
+ Hypothesis H_respects_policy:
+ respects_JLFP_policy_at_preemption_point
+ job_arrival job_cost arr_seq sched
+ can_be_preempted_for_fully_preemptive_model higher_eq_priority.
+
+ (* Let L be any positive fixed point of the busy interval recurrence,
+ determined by the higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = total_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A :=
+ (A < L) && (task_rbf_changes_at A  bound_on_total_hep_workload_changes_at A).
+
+ (* Consider any value R, and assume that for any given arrival offset A in the search space,
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = task_rbf (A + ε) + bound_on_total_hep_workload A (A + F) /\
+ F <= R.
+
+ (* Now, we can leverage the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model of fully preemptive scheduling. *)
+ Theorem uniprocessor_response_time_bound_fully_preemptive_edf:
+ response_time_bounded_by tsk R.
+ Proof.
+ have BLOCK: RTAforEDFwithBoundedNonpreemptiveSegmentsWithArrivalCurves.blocking_bound
+ (fun _ => ε) D ts tsk = 0.
+ { by rewrite /RTAforEDFwithBoundedNonpreemptiveSegmentsWithArrivalCurves.blocking_bound
+ subnn big1_eq. }
+ eapply uniprocessor_response_time_bound_edf_with_bounded_nonpreemptive_segments with
+ (task_max_nps := fun _ => ε)
+ (can_be_preempted := fun j prog => true)
+ (task_lock_in_service := fun tsk => task_cost tsk)
+ (job_lock_in_service := fun j => job_cost j)
+ (job_max_nps := fun j => ε); eauto 2; try done.
+  by eapply fully_preemptive_model_is_model_with_bounded_nonpreemptive_regions.
+  repeat split; try done.
+ intros ? ? ? ARR; move => LE COMPL /negP NCOMPL.
+ exfalso; apply: NCOMPL.
+ apply completion_monotonic with t; try done.
+  repeat split; try done.
+ rewrite /task_lock_in_service_le_task_cost. by done.
+ unfold task_lock_in_service_bounds_job_lock_in_service.
+ by intros ? ARR TSK; rewrite TSK; apply H_job_cost_le_task_cost.
+  by rewrite BLOCK add0n.
+  move => A /andP [LT NEQ].
+ specialize (H_R_is_maximum A); feed H_R_is_maximum.
+ { by apply/andP; split. }
+ move: H_R_is_maximum => [F [FIX BOUND]].
+ exists F; split.
+ + by rewrite BLOCK add0n subnn subn0.
+ + by rewrite subnn addn0.
+ Qed.
+
+ End RTAforFullyPreemptiveEDFModelwithArrivalCurves.
+
+ (** * RTA for fully nonpreemptive EDF model *)
+ (** In this section we prove the RTA theorem for the fully nonpreemptive EDF model. *)
+ Section RTAforFullyNonPreemptiveEDFModelwithArrivalCurves.
+
+ (* First, we assume that the schedule is nonpreemptive. *)
+ Hypothesis H_nonpreemptive_sched: is_nonpreemptive_schedule job_cost sched.
+
+ (* Next, we assume that the schedule respects the JLFP policy
+ under a model with fixed preemption points. *)
+ Hypothesis H_respects_policy:
+ respects_JLFP_policy_at_preemption_point
+ job_arrival job_cost arr_seq sched
+ (can_be_preempted_for_fully_nonpreemptive_model job_cost) higher_eq_priority.
+
+ (* We also define a bound for the priority inversion caused by jobs with lower priority. *)
+ Let blocking_bound :=
+ \max_(tsk_other < ts  (tsk_other != tsk) && (D tsk_other > D tsk))
+ (task_cost tsk_other  ε).
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A :=
+ (A < L) && (task_rbf_changes_at A  bound_on_total_hep_workload_changes_at A).
+
+ (* Consider any value R, and assume that for any given arrival offset A in the search space,
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound + (task_rbf (A + ε)  (task_cost tsk  ε))
+ + bound_on_total_hep_workload A (A + F) /\
+ F + (task_cost tsk  ε) <= R.
+
+ (* Now, we can leverage the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model of fully nonpreemptive scheduling. *)
+ Theorem uniprocessor_response_time_bound_fully_nonpreemptive_edf:
+ response_time_bounded_by tsk R.
+ Proof.
+ move: (posnP (task_cost tsk)) => [ZEROPOS].
+ { intros j ARR TSK.
+ have ZEROj: job_cost j = 0.
+ { move: (H_job_cost_le_task_cost j ARR) => NEQ.
+ rewrite /job_cost_le_task_cost TSK ZERO in NEQ.
+ by apply/eqP; rewrite leqn0.
+ }
+ by rewrite /is_response_time_bound_of_job /completed_by ZEROj.
+ }
+ eapply uniprocessor_response_time_bound_edf_with_bounded_nonpreemptive_segments with
+ (job_max_nps := fun j => job_cost j)
+ (task_max_nps := fun tsk => task_cost tsk)
+ (job_lock_in_service := fun j => ε)
+ (task_lock_in_service := fun tsk => ε)
+ (L0 := L); eauto 2.
+  by eapply fully_nonpreemptive_model_is_correct; eauto 2.
+  eapply fully_nonpreemptive_model_is_model_with_bounded_nonpreemptive_regions; eauto 2.
+  repeat split; try done.
+  intros j t t' ARR LE SERV NCOMPL.
+ rewrite /service in SERV; apply incremental_service_during in SERV.
+ move: SERV => [t_first [/andP [_ H1] [H2 H3]]].
+ apply H_nonpreemptive_sched with t_first; try done.
+ by apply leq_trans with t; first apply ltnW.
+  repeat split; try done.
+ Qed.
+
+ End RTAforFullyNonPreemptiveEDFModelwithArrivalCurves.
+
+ (** * RTA for EDF with fixed premption points *)
+ (** In this module we prove a general RTA theorem for EDFschedulers with fixed preemption points *)
+ Section RTAforFixedPreemptionPointsModelwithArrivalCurves.
+
+ (* First, let's assume we have the model with fixed preemption points.
+ I.e., each task is divided into a number of nonpreemptive segments
+ separated by statically predefined preemption points. *)
+ Variable job_preemption_points: Job > seq time.
+ Variable task_preemption_points: Task > seq time.
+ Hypothesis H_model_with_fixed_preemption_points:
+ fixed_preemption_points_model
+ task_cost job_cost job_task arr_seq
+ job_preemption_points task_preemption_points ts.
+
+ (* Assume that the schedule is a uniprocessor schedule with limited preemptions... *)
+ Hypothesis H_schedule_with_limited_preemptions:
+ is_schedule_with_limited_preemptions arr_seq job_preemption_points sched.
+
+ (* ... that respects the JLFP policy under a model with fixed preemption points. *)
+ Hypothesis H_respects_policy:
+ respects_JLFP_policy_at_preemption_point
+ job_arrival job_cost arr_seq sched
+ (can_be_preempted_for_model_with_limited_preemptions job_preemption_points) higher_eq_priority.
+
+ (* We also have a set of functions that map job or task
+ to its max or last nonpreemptive segment. *)
+ Let job_max_nps := job_max_nps job_preemption_points.
+ Let job_last_nps := job_last_nps job_preemption_points.
+ Let task_max_nps := task_max_nps task_preemption_points.
+ Let task_last_nps := task_last_nps task_preemption_points.
+
+ (* We define a bound for the priority inversion caused by jobs with lower priority. *)
+ Let blocking_bound :=
+ \max_(tsk_other < ts  (tsk_other != tsk) && (D tsk_other > D tsk))
+ (task_max_nps tsk_other  ε).
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A :=
+ (A < L) && (task_rbf_changes_at A  bound_on_total_hep_workload_changes_at A).
+
+ (* Consider any value R, and assume that for any given arrival offset A in the search space,
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound
+ + (task_rbf (A + ε)  (task_last_nps tsk  ε))
+ + bound_on_total_hep_workload A (A + F) /\
+ F + (task_last_nps tsk  ε) <= R.
+
+ (* Now, we can leverage the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model of fixed preemption points. *)
+ Theorem uniprocessor_response_time_bound_edf_with_fixed_preemption_points:
+ response_time_bounded_by tsk R.
+ Proof.
+ move: (H_model_with_fixed_preemption_points) => [MLP [BEG [END [INCR [HYP1 [HYP2 HYP3]]]]]].
+ move: (MLP) => [EMPTj [LSMj [BEGj [ENDj HH]]]].
+ move: (posnP (task_cost tsk)) => [ZEROPOSt].
+ { intros j ARR TSK.
+ move: (H_job_cost_le_task_cost _ ARR) => POSt.
+ move: POSt; rewrite /job_cost_le_task_cost TSK ZERO leqn0; move => /eqP Z.
+ by rewrite /is_response_time_bound_of_job /completed_by Z.
+ }
+ have Fact2: 1 < size (task_preemption_points tsk).
+ { have Fact2: 0 < size (task_preemption_points tsk).
+ { apply/negPn/negP; rewrite eqn0Ngt; intros CONTR; move: CONTR => /eqP CONTR.
+ move: (END _ H_tsk_in_ts) => EQ.
+ move: EQ; rewrite /NondecreasingSequence.last nth_last nth_default; last by rewrite CONTR.
+ by intros; rewrite EQ in POSt.
+ }
+ have EQ: 2 = size [::0; task_cost tsk]; first by done.
+ rewrite EQ; clear EQ.
+ apply subseq_leq_size.
+ rewrite !cons_uniq.
+ { apply/andP; split.
+ rewrite in_cons negb_or; apply/andP; split; last by done.
+ rewrite neq_ltn; apply/orP; left; eauto 2.
+ apply/andP; split; by done. }
+ intros t EQ; move: EQ; rewrite !in_cons.
+ move => /orP [/eqP EQ /orP [/eqP EQEQ]]; last by done.
+ { rewrite EQ; clear EQ.
+ move: (BEG _ H_tsk_in_ts) => EQ.
+ rewrite EQ; clear EQ.
+ rewrite /NondecreasingSequence.first nth0.
+ apply/(nthP 0).
+ exists 0; by done.
+ }
+ { rewrite EQ; clear EQ.
+ move: (END _ H_tsk_in_ts) => EQ.
+ rewrite EQ; clear EQ.
+ rewrite /NondecreasingSequence.last nth_last.
+ apply/(nthP 0).
+ exists ((size (task_preemption_points tsk)).1); last by done.
+ by rewrite (leq_add2r 1) !addn1 prednK //.
+ }
+ }
+ eapply uniprocessor_response_time_bound_edf_with_bounded_nonpreemptive_segments
+ with (task_lock_in_service := fun tsk => (task_cost tsk  (task_last_nps tsk  ε)))
+ (job_lock_in_service := fun job => (job_cost job  (job_last_nps job  ε)))
+ (L0 := L) (job_max_nps0 := job_max_nps)
+ (job_cost0 := job_cost )
+ ; eauto 2.
+ { by apply model_with_fixed_preemption_points_is_correct. }
+ { eapply model_with_fixed_preemption_points_is_model_with_bounded_nonpreemptive_regions; eauto 2.
+ intros j ARR.
+ unfold ModelWithLimitedPreemptions.job_max_nps, task_max_nps, lengths_of_segments.
+ apply NondecreasingSequence.max_of_dominating_seq.
+ intros. apply HYP2.
+ by done.
+ }
+ { split; last split.
+ { intros j ARR POS.
+ rewrite subn_gt0.
+ rewrite subn1 (leq_add2r 1) !addn1 prednK; last first.
+ apply LSMj; try done.
+ rewrite /job_last_nps /ModelWithLimitedPreemptions.job_last_nps
+ ltnS /NondecreasingSequence.last nth_last NondecreasingSequence.function_of_distances_is_correct.
+ apply leq_trans with (job_max_nps j);
+ first by apply NondecreasingSequence.distance_between_neighboring_elements_le_max_distance_in_seq.
+ rewrite ENDj; last by done.
+ by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ { by intros j ARR; rewrite leq_subLR leq_addl. }
+ { intros ? ? ? ARR LE LS NCOMPL.
+ rewrite subnBA in LS; last first.
+ apply LSMj; try done.
+ { rewrite lt0n; apply/negP; intros Z; move: Z => /eqP Z.
+ by move: NCOMPL; rewrite /completed_by ltnNge Z ltn0; move => LT.
+ }
+ have EQ: exists Δ, t' = t + Δ.
+ { exists (t'  t); rewrite subnKC; by done. }
+ move: EQ => [Δ EQ]; subst t'; clear LE.
+ rewrite subh1 in LS.
+ rewrite addn1 in LS.
+ apply H_schedule_with_limited_preemptions; first by done.
+ rewrite /can_be_preempted_for_model_with_limited_preemptions; apply/negP.
+ intros CONTR.
+ move: NCOMPL; rewrite /completed_by ltnNge; move => SERV.
+ have NEQ: job_cost j  job_last_nps j < service sched j (t + Δ).
+ { apply leq_trans with (service sched j t); first by done.
+ rewrite /service /service_during [in X in _ <= X](@big_cat_nat _ _ _ t) //=.
+ rewrite leq_addr //.
+ rewrite leq_addr //.
+ }
+ clear LS.
+ rewrite ENDj in NEQ, SERV; last by done.
+ rewrite NondecreasingSequence.last_seq_minus_last_distance_seq in NEQ; last by eauto 2.
+ rewrite /NondecreasingSequence.last nth_last in SERV.
+ have EQ := NondecreasingSequence.antidensity_of_nondecreasing_seq.
+ specialize (EQ (job_preemption_points j) (service sched j (t + Δ)) (size (job_preemption_points j)).2).
+ rewrite CONTR in EQ.
+ feed_n 2 EQ; first by eauto 2.
+ {
+ apply/andP; split; first by done.
+ rewrite prednK; first by done.
+ rewrite (leq_add2r 1) !addn1 prednK.
+ eapply number_of_preemption_points_at_least_two with (job_cost0 := job_cost); eauto 2.
+ eapply list_of_preemption_point_is_not_empty with (job_cost0 := job_cost); eauto 2.
+ }
+ by done.
+
+ rewrite ENDj; last by done.
+ apply leq_trans with (job_max_nps j).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ }
+ {
+ split.
+  by rewrite /task_lock_in_service_le_task_cost leq_subLR leq_addl.
+  intros j ARR TSK.
+ move: (posnP (job_cost j)) => [ZERO  POS].
+ { by rewrite ZERO. }
+ unfold task_last_nps.
+ rewrite !subnBA; first last.
+ apply LSMj; try done.
+ rewrite /ModelWithLimitedPreemptions.task_last_nps /NondecreasingSequence.last nth_last.
+ apply HYP3.
+ by done.
+ rewrite (ltn_add2r 1) !addn1 prednK //.
+ move: (Fact2) => Fact3.
+ rewrite NondecreasingSequence.size_of_seq_of_distances // addn1 ltnS // in Fact2.
+ rewrite subh1 ?[in X in _ <= X]subh1; first last.
+ { apply leq_trans with (job_max_nps j).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by rewrite ENDj //; apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ { apply leq_trans with (task_max_nps tsk).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by rewrite END //; apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ rewrite ENDj; last eauto 2.
+ rewrite END; last eauto 2.
+ rewrite !NondecreasingSequence.last_seq_minus_last_distance_seq.
+ have EQ: size (job_preemption_points j) = size (task_preemption_points tsk).
+ { rewrite TSK.
+ by apply HYP1.
+ }
+ rewrite EQ; clear EQ.
+ rewrite leq_add2r.
+ apply NondecreasingSequence.domination_of_distances_implies_domination_of_seq; try done; eauto 2.
+ rewrite BEG // BEGj //.
+ eapply number_of_preemption_points_at_least_two with (job_cost0 := job_cost); eauto 2.
+ rewrite TSK; apply HYP1; try done.
+ intros. rewrite TSK; eauto 2.
+ eauto 2.
+ eauto 2.
+ }
+ { rewrite subKn; first by done.
+ rewrite /task_last_nps (leq_add2r 1) subn1 !addn1 prednK; last first.
+ { rewrite /ModelWithLimitedPreemptions.task_last_nps /NondecreasingSequence.last nth_last.
+ apply HYP3; try by done.
+ rewrite (ltn_add2r 1) !addn1 prednK //.
+ move: (Fact2) => Fact3.
+ by rewrite NondecreasingSequence.size_of_seq_of_distances // addn1 ltnS // in Fact2.
+ }
+ { apply leq_trans with (task_max_nps tsk).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  rewrite END; last by done.
+ apply ltnW; rewrite ltnS; try done.
+ by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ }
+ Qed.
+
+ End RTAforFixedPreemptionPointsModelwithArrivalCurves.
+
+ (** * RTA for EDF with floating nonpreemptive regions *)
+ (** In this module we prove a general RTA theorem for EDFschedulers with floating nonpreemptive regions *)
+ Section RTAforModelWithFloatingNonpreemptiveRegionsWithArrivalCurves.
+
+ (* First, assume we have model with floating nonpreemptive regions.
+ I.e., for each task only the length of the maximal nonpreemptive
+ segment is known. *)
+ Variable job_preemption_points: Job > seq time.
+ Variable task_max_nps: Task > time.
+ Hypothesis H_task_model_with_floating_nonpreemptive_regions:
+ model_with_floating_nonpreemptive_regions
+ job_cost job_task arr_seq job_preemption_points task_max_nps.
+
+ (* Assume that the schedule is a uniprocessor schedule with limited preemptions... *)
+ Hypothesis H_schedule_with_limited_preemptions:
+ is_schedule_with_limited_preemptions arr_seq job_preemption_points sched.
+
+ (* ... that respects the JLFP policy under a model with floating nonpreemptive regions. *)
+ Hypothesis H_respects_policy:
+ respects_JLFP_policy_at_preemption_point
+ job_arrival job_cost arr_seq sched
+ (can_be_preempted_for_model_with_limited_preemptions job_preemption_points) higher_eq_priority.
+
+ (* We also have two functions that map job to its max or last nonpreemptive segment. *)
+ Let job_max_nps := job_max_nps job_preemption_points.
+ Let job_last_nps := job_last_nps job_preemption_points.
+
+ (* We define a bound for the priority inversion caused by jobs with lower priority. *)
+ Definition blocking_bound :=
+ \max_(tsk_other < ts  (tsk_other != tsk) && (D tsk_other > D tsk))
+ (task_max_nps tsk_other  ε).
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A :=
+ (A < L) && (task_rbf_changes_at A  bound_on_total_hep_workload_changes_at A).
+
+ (* Consider any value R, and assume that for any given arrival offset A in the search space,
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound + task_rbf (A + ε) + bound_on_total_hep_workload A (A + F) /\
+ F <= R.
+
+ (* Now, we can leverage the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model with floating nonpreemptive regions. *)
+ Theorem uniprocessor_response_time_bound_edf_with_floating_nonpreemptive_regions:
+ response_time_bounded_by tsk R.
+ Proof.
+ move: (H_task_model_with_floating_nonpreemptive_regions) => [LIMJ JMLETM].
+ move: (LIMJ) => [ZERO [LSMj [BEG [END HH]]]].
+ eapply uniprocessor_response_time_bound_edf_with_bounded_nonpreemptive_segments
+ with (task_lock_in_service := fun tsk => task_cost tsk)
+ (job_lock_in_service := fun job => (job_cost job  (job_last_nps job  ε)))
+ (L0 := L) (job_max_nps0 := job_max_nps)
+ (job_cost0 := job_cost )
+ ; eauto 2.
+ { by apply model_with_fixed_preemption_points_is_correct. }
+ { by eapply model_with_fixed_preemption_points_is_model_with_bounded_nonpreemptive_regions; eauto 2. }
+ { split; last split.
+ { intros j ARR POS.
+ rewrite subn_gt0.
+ rewrite subn1 (leq_add2r 1) !addn1 prednK; last first.
+ apply LSMj; try done.
+ rewrite /job_last_nps /ModelWithLimitedPreemptions.job_last_nps
+ ltnS /NondecreasingSequence.last nth_last NondecreasingSequence.function_of_distances_is_correct.
+ apply leq_trans with (job_max_nps j); first by apply NondecreasingSequence.distance_between_neighboring_elements_le_max_distance_in_seq.
+ rewrite END; last by done.
+ by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ { by intros j ARR; rewrite leq_subLR leq_addl. }
+ { intros ? ? ? ARR LE LS NCOMPL.
+ rewrite subnBA in LS; last first.
+ apply LSMj; try done.
+ { rewrite lt0n; apply/negP; intros Z; move: Z => /eqP Z.
+ by move: NCOMPL; rewrite /completed_by ltnNge Z ltn0.
+ }
+ have EQ: exists Δ, t' = t + Δ.
+ { exists (t'  t); rewrite subnKC; by done. }
+ move: EQ => [Δ EQ]; subst t'; clear LE.
+ rewrite subh1 in LS.
+ rewrite addn1 in LS.
+ apply H_schedule_with_limited_preemptions; first by done.
+ rewrite /can_be_preempted_for_model_with_limited_preemptions; apply/negP.
+ intros CONTR.
+ move: NCOMPL; rewrite /completed_by ltnNge; move => SERV.
+ have NEQ: job_cost j  (job_last_nps j) < service sched j (t + Δ).
+ { apply leq_trans with (service sched j t); first by done.
+ rewrite /service /service_during [in X in _ <= X](@big_cat_nat _ _ _ t) //=.
+ rewrite leq_addr //.
+ rewrite leq_addr //.
+ }
+ clear LS.
+ rewrite END in NEQ, SERV; last by done.
+ rewrite NondecreasingSequence.last_seq_minus_last_distance_seq in NEQ.
+ rewrite /NondecreasingSequence.last nth_last in SERV.
+ have EQ := NondecreasingSequence.antidensity_of_nondecreasing_seq.
+ specialize (EQ (job_preemption_points j) (service sched j (t + Δ)) (size (job_preemption_points j)).2).
+ rewrite CONTR in EQ.
+ feed_n 2 EQ; first by eauto 2.
+ {
+ apply/andP; split; first by done.
+ rewrite prednK; first by done.
+ rewrite (leq_add2r 1) !addn1 prednK.
+ eapply number_of_preemption_points_at_least_two with (job_cost0 := job_cost); eauto 2.
+ eapply list_of_preemption_point_is_not_empty with (job_cost0 := job_cost); eauto 2.
+ }
+ by done.
+ eauto 2.
+ rewrite END; last by done.
+ apply leq_trans with (job_max_nps j).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ }
+ {
+ split.
+  by rewrite /task_lock_in_service_le_task_cost.
+  intros j ARR TSK.
+ apply leq_trans with (job_cost j); first by rewrite leq_subr.
+ by rewrite TSK; eauto 2.
+ }
+ {
+ rewrite subnn.
+ intros.
+ apply H_R_is_maximum in H.
+ move: H => [F [EQ LE]].
+ exists F.
+ by rewrite subn0 addn0; split.
+ }
+ Qed.
+
+ End RTAforModelWithFloatingNonpreemptiveRegionsWithArrivalCurves.
+
+ End Analysis.
+
+End RTAforConcreteModels.
\ No newline at end of file
diff git a/model/schedule/uni/limited/edf/nonpr_reg/response_time_bound.v b/model/schedule/uni/limited/edf/nonpr_reg/response_time_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..4e59075ba5940ed07d60f6ef03eec53788ac8d70
 /dev/null
+++ b/model/schedule/uni/limited/edf/nonpr_reg/response_time_bound.v
@@ 0,0 +1,344 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time.
+Require Import rt.model.schedule.uni.limited.platform.definitions
+ rt.model.schedule.uni.limited.platform.priority_inversion_is_bounded
+ rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.busy_interval
+ rt.model.schedule.uni.limited.edf.response_time_bound
+ rt.model.schedule.uni.limited.rbf.
+Require Import rt.model.arrival.curves.bounds.
+Require Import rt.analysis.uni.arrival_curves.workload_bound.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * RTA for EDFschedulers with bounded nonpreemprive segments *)
+(** In this module we prove a general RTA theorem for EDFschedulers. *)
+Module RTAforEDFwithBoundedNonpreemptiveSegmentsWithArrivalCurves.
+
+ Import Epsilon Job ArrivalCurves TaskArrival Priority UniprocessorSchedule Workload Service
+ ResponseTime MaxArrivalsWorkloadBound LimitedPreemptionPlatform RBF
+ AbstractRTAforEDFwithArrivalCurves BusyIntervalJLFP PriorityInversionIsBounded.
+
+ Section Analysis.
+
+ Context {Task: eqType}.
+ Variable task_max_nps task_cost: Task > time.
+ Variable task_deadline: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_max_nps job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* For clarity, let's denote the relative deadline of a task as D. *)
+ Let D tsk := task_deadline tsk.
+
+ (* The relative deadline of a job is equal to the deadline of the corresponding task. *)
+ Let job_relative_deadline j := D (job_task j).
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals... *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Assume we have sequential jobs, i.e, jobs from the same
+ task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Consider the EDF policy that indicates a higherorequal priority relation. *)
+ Let higher_eq_priority: JLFP_policy Job := EDF job_arrival job_relative_deadline.
+
+ (* We consider an arbitrary function can_be_preempted which defines
+ a preemption model with bounded nonpreemptive segments. *)
+ Variable can_be_preempted: Job > time > bool.
+ Let preemption_time := preemption_time sched can_be_preempted.
+ Hypothesis H_correct_preemption_model:
+ correct_preemption_model arr_seq sched can_be_preempted.
+ Hypothesis H_model_with_bounded_nonpreemptive_segments:
+ model_with_bounded_nonpreemptive_segments
+ job_cost job_task arr_seq can_be_preempted job_max_nps task_max_nps.
+
+ (* Next, we assume that the schedule is a workconserving schedule... *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* ... and the schedule respects the policy defined by the
+ can_be_preempted function (i.e., bounded nonpreemptive segments). *)
+ Hypothesis H_respects_policy:
+ respects_JLFP_policy_at_preemption_point
+ job_arrival job_cost arr_seq sched can_be_preempted higher_eq_priority.
+
+ (* Consider an arbitrary task set ts. *)
+ Variable ts: list Task.
+
+ (* Assume that all jobs come from the task set... *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* ...and the cost of a job cannot be larger than the task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Consider a proper job lockin service and task lockin functions, i.e... *)
+ Variable job_lock_in_service: Job > time.
+ Variable task_lock_in_service: Task > time.
+
+ (* ...we assume that for all jobs in the arrival sequence the lockin service is
+ (1) positive, (2) no bigger than costs of the corresponding jobs, and (3) a job
+ becomes nonpreemptive after it reaches its lockin service... *)
+ Hypothesis H_proper_job_lock_in_service:
+ proper_job_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* ...and that [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any
+ job of task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Hypothesis H_proper_task_lock_in_service:
+ proper_task_lock_in_service
+ task_cost job_task arr_seq job_lock_in_service task_lock_in_service tsk.
+
+ (* We introduce as an abbreviation "rbf" for the task request bound function,
+ which is defined as [task_cost(T) × max_arrivals(T,Δ)] for a task T. *)
+ Let rbf := task_request_bound_function task_cost max_arrivals.
+
+ (* Next, we introduce task_rbf as an abbreviation for the task
+ request bound function of task tsk. *)
+ Let task_rbf := rbf tsk.
+
+ (* Using the sum of individual request bound functions, we define the request bound
+ function of all tasks (total request bound function). *)
+ Let total_rbf := total_request_bound_function task_cost max_arrivals ts.
+
+ (* Next, we define an upper bound on interfering workload received from jobs
+ of other tasks with higherthanorequal priority. *)
+ Let bound_on_total_hep_workload A Δ :=
+ \sum_(tsk_o < ts  tsk_o != tsk)
+ rbf tsk_o (minn ((A + ε) + D tsk  D tsk_o) Δ).
+
+ (* Let's define some local names for clarity. *)
+ Let job_pending_at := pending job_arrival job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_backlogged_at := backlogged job_arrival job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let task_rbf_changes_at A := task_rbf_changes_at task_cost max_arrivals tsk A.
+ Let bound_on_total_hep_workload_changes_at :=
+ bound_on_total_hep_workload_changes_at task_cost task_deadline ts max_arrivals tsk.
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+ Let max_length_of_priority_inversion :=
+ max_length_of_priority_inversion job_max_nps arr_seq higher_eq_priority.
+
+ (* We also define a bound for the priority inversion caused by jobs with lower priority. *)
+ Definition blocking_bound :=
+ \max_(tsk_other < ts  (tsk_other != tsk) && (D tsk < D tsk_other))
+ (task_max_nps tsk_other  ε).
+
+ (** ** Priority inversion is bounded *)
+ (** In this section, we prove that a priority inversion for task tsk is bounded by
+ the maximum length of nonpreemtive segments among the tasks with lower priority. *)
+ Section PriorityInversionIsBounded.
+
+ (* First, we prove that the maximum length of a priority inversion of job j is
+ bounded by the maximum length of a nonpreemptive section of a task with
+ lowerpriority task (i.e., the blocking term). *)
+ Lemma priority_inversion_is_bounded_by_blocking:
+ forall j t,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ t <= job_arrival j >
+ max_length_of_priority_inversion j t <= blocking_bound.
+ Proof.
+ intros j t ARR TSK LE.
+ unfold max_length_of_priority_inversion, blocking_bound.
+ apply leq_trans with
+ (\max_(j_lp < jobs_arrived_between arr_seq 0 t 
+ ~~ higher_eq_priority j_lp j)
+ (task_max_nps (job_task j_lp)  ε)
+ ).
+ { apply leq_big_max.
+ intros j' JINB NOTHEP.
+ specialize (H_job_cost_le_task_cost j').
+ feed H_job_cost_le_task_cost.
+ { apply mem_bigcat_nat_exists in JINB.
+ by move: JINB => [ta' [JIN' _]]; exists ta'.
+ }
+ rewrite leq_sub2r //.
+ apply in_arrivals_implies_arrived in JINB.
+ move: (H_model_with_bounded_nonpreemptive_segments j' JINB) => [_ [_ [T _]]].
+ by apply T.
+ }
+ { apply /bigmax_leq_seqP.
+ intros j' JINB NOTHEP.
+ apply leq_bigmax_cond_seq with
+ (i0 := (job_task j')) (F := fun tsk => task_max_nps tsk  1).
+ { apply H_all_jobs_from_taskset.
+ apply mem_bigcat_nat_exists in JINB.
+ by inversion JINB as [ta' [JIN' _]]; exists ta'. }
+ { have NINTSK: job_task j' != tsk.
+ { apply/eqP; intros TSKj'.
+ rewrite /higher_eq_priority /EDF ltnNge in NOTHEP.
+ rewrite /job_relative_deadline TSKj' TSK ltn_add2r in NOTHEP.
+ move: NOTHEP; rewrite ltnNge; move => /negP T; apply: T.
+ apply leq_trans with t; last by done.
+ eapply in_arrivals_implies_arrived_between in JINB; last by eauto 2.
+ move: JINB; move => /andP [_ T].
+ by apply ltnW.
+ }
+ apply/andP; split; first by done.
+ rewrite /higher_eq_priority /EDF /job_relative_deadline ltnNge in NOTHEP.
+ rewrite TSK.
+ have ARRLE: job_arrival j' < job_arrival j.
+ { apply leq_trans with t; last by done.
+ eapply in_arrivals_implies_arrived_between in JINB; last by eauto 2.
+ by move: JINB; move => /andP [_ T].
+ }
+ have F: forall a b c d, a + b < c + d > a > c > b < d.
+ { clear.
+ intros.
+ rewrite addn1 addnA leq_subLR subh1 in H; last by apply ltnW.
+ rewrite addn1 addnS in H.
+ rewrite subn_gt0 in H0.
+ apply ltn_trans with (a  c + b); last by done.
+ apply ltn_subLR.
+ have EQ: b  b = 0. apply/eqP. rewrite subn_eq0. by done.
+ by rewrite EQ.
+ }
+ eapply F; eauto 2.
+ }
+ }
+ Qed.
+
+ (* Using the lemma above, we prove that the priority inversion of the task is bounded by
+ the maximum length of a nonpreemptive section of lowerpriority tasks. *)
+ Lemma priority_inversion_is_bounded:
+ priority_inversion_is_bounded_by
+ job_arrival job_cost job_task arr_seq sched higher_eq_priority tsk blocking_bound.
+ Proof.
+ intros j ARR TSK POS t1 t2 PREF.
+ move: (PREF) => [_ [_ [_ /andP [T _]]]].
+ case NEQ: (t2  t1 <= blocking_bound).
+ { apply leq_trans with (t2  t1); last by done.
+ rewrite /cumulative_priority_inversion /is_priority_inversion.
+ rewrite [X in _ <= X]addn0 [t2  t1]mul1n iter_addn big_const_nat.
+ rewrite leq_sum //.
+ intros t _; case: (sched t); last by done.
+ by intros s; case: (higher_eq_priority).
+ }
+ move: NEQ => /negP /negP; rewrite ltnNge; move => NEQ.
+ have PPE := preemption_time_exists
+ task_max_nps job_arrival job_max_nps job_cost job_task arr_seq
+ _ sched _ _ _ higher_eq_priority _ _ can_be_preempted
+ _ _ _ _ j _ _ t1 t2.
+ feed_n 13 PPE; try done.
+ { by apply EDF_is_reflexive. }
+ { by apply EDF_is_transitive. }
+ move: PPE => [ppt [PPT /andP [GE LE]]].
+ apply leq_trans with (cumulative_priority_inversion sched higher_eq_priority j t1 ppt);
+ last apply leq_trans with (ppt  t1).
+ { rewrite /cumulative_priority_inversion /is_priority_inversion.
+ rewrite (@big_cat_nat _ _ _ ppt) //=.
+ rewrite [X in _ <= X]addn0 leq_add2l.
+ rewrite leqn0.
+ rewrite big_nat_cond big1 //; move => t /andP [/andP [GEt LTt] _ ].
+ case SCHED: (sched t) => [s  ]; last by done.
+ have SCHEDHP := not_quiet_implies_exists_scheduled_hp_job
+ task_max_nps job_arrival job_max_nps job_cost job_task arr_seq
+ _ sched _ _ _ higher_eq_priority _ _ can_be_preempted
+ _ _ _ _ j _ _ t1 t2 _ (ppt  t1) _ t.
+ feed_n 15 SCHEDHP; try done.
+ { by apply EDF_is_reflexive. }
+ { by apply EDF_is_transitive. }
+ { exists ppt; split. by done. by rewrite subnKC //; apply/andP; split. }
+ { by rewrite subnKC //; apply/andP; split. }
+ move: SCHEDHP => [j_hp [ARRB [HP SCHEDHP]]].
+ apply/eqP; rewrite eqb0 Bool.negb_involutive.
+ have EQ: s = j_hp.
+ { by apply only_one_job_scheduled with (sched0 := sched) (t0 := t); [apply/eqP  ]. }
+ by rewrite EQ.
+ rewrite ltn_subRL in NEQ.
+ apply leq_trans with (t1 + blocking_bound); last by apply ltnW.
+ apply leq_trans with (t1 + max_length_of_priority_inversion j t1); first by done.
+ by rewrite leq_add2l; eapply priority_inversion_is_bounded_by_blocking; eauto 2.
+ }
+ { rewrite /cumulative_priority_inversion /is_priority_inversion.
+ rewrite [X in _ <= X]addn0 [ppt  t1]mul1n iter_addn big_const_nat.
+ rewrite leq_sum //.
+ intros t _; case: (sched t); last by done.
+ by intros s; case: higher_eq_priority.
+ }
+ { rewrite leq_subLR.
+ apply leq_trans with (t1 + max_length_of_priority_inversion j t1); first by done.
+ rewrite leq_add2l; eapply priority_inversion_is_bounded_by_blocking; eauto 2.
+ }
+ Qed.
+
+ End PriorityInversionIsBounded.
+
+ (** ** ResponseTime Bound *)
+ (** In this section, we prove that the maximum among the solutions of the responsetime
+ bound recurrence is a responsetime bound for tsk. *)
+ Section ResponseTimeBound.
+
+ (* Let L be any positive fixed point of the busy interval recurrence. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A :=
+ (A < L) && (task_rbf_changes_at A  bound_on_total_hep_workload_changes_at A).
+
+ (* Consider any value R, and assume that for any given arrival offset A in the search space,
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound
+ + (task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk))
+ + bound_on_total_hep_workload A (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+ (* Then, using the results for the general RTA for EDFschedulers, we establish a
+ responsetime bound for the more concrete model of bounded nonpreemptive segments.
+ Note that in case of the general RTA for EDFschedulers, we just _assume_ that
+ the priority inversion is bounded. In this module we provide the preemption model
+ with bounded nonpreemptive segments and _prove_ that the priority inversion is
+ bounded. *)
+ Theorem uniprocessor_response_time_bound_edf_with_bounded_nonpreemptive_segments:
+ response_time_bounded_by tsk R.
+ Proof.
+ eapply uniprocessor_response_time_bound_edf; eauto 2.
+ by apply priority_inversion_is_bounded.
+ Qed.
+
+ End ResponseTimeBound.
+
+ End Analysis.
+
+End RTAforEDFwithBoundedNonpreemptiveSegmentsWithArrivalCurves.
\ No newline at end of file
diff git a/model/schedule/uni/limited/edf/response_time_bound.v b/model/schedule/uni/limited/edf/response_time_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..840d5e829ee4c6180f2c166d3a71e1de9f7c4cab
 /dev/null
+++ b/model/schedule/uni/limited/edf/response_time_bound.v
@@ 0,0 +1,657 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time
+ rt.model.schedule.uni.schedule_of_task.
+Require Import rt.model.schedule.uni.limited.platform.definitions
+ rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.busy_interval
+ rt.model.schedule.uni.limited.rbf
+ rt.model.schedule.uni.limited.abstract_RTA.definitions
+ rt.model.schedule.uni.limited.abstract_RTA.reduction_of_search_space
+ rt.model.schedule.uni.limited.abstract_RTA.abstract_seq_rta
+ rt.model.schedule.uni.limited.jlfp_instantiation.
+Require Import rt.model.arrival.curves.bounds.
+Require Import rt.analysis.uni.arrival_curves.workload_bound.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Abstract RTA for EDFschedulers *)
+(** In this module we propose the abstract responsetime analysis (RTA) for
+ EDF uniprocessor scheduling of realtime tasks with arbitrary arrival models. *)
+Module AbstractRTAforEDFwithArrivalCurves.
+
+ Import Job Epsilon ArrivalCurves TaskArrival ScheduleOfTask Priority
+ UniprocessorSchedule Workload Service ResponseTime MaxArrivalsWorkloadBound
+ BusyIntervalJLFP LimitedPreemptionPlatform RBF Service JLFPInstantiation.
+
+ Section AbstractResponseTimeAnalysisForEDF.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+ Variable task_deadline: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* For clarity, let's denote the relative deadline of a task as D. *)
+ Let D tsk := task_deadline tsk.
+
+ (* The relative deadline of a job is equal to the deadline of the corresponding task. *)
+ Let job_relative_deadline j := D (job_task j).
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Next, assume that the schedule is a workconserving schedule. *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* Assume we have sequential jobs, i.e, jobs from the
+ same task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Assume that a job cost cannot be larger than a task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Consider an arbitrary task set ts. *)
+ Variable ts: list Task.
+
+ (* Next, we assume that all jobs come from the task set. *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Consider proper job lockin service and task lockin functions, i.e... *)
+ Variable job_lock_in_service: Job > time.
+ Variable task_lock_in_service: Task > time.
+
+ (* ...we assume that for all jobs with positive cost in the arrival sequence the
+ lockin service is (1) positive, (2) no bigger than costs of the corresponding
+ jobs, and (3) a job becomes nonpreemptive after it reaches its lockin service... *)
+ Hypothesis H_proper_job_lock_in_service:
+ proper_job_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* ...and that [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any
+ job of task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Hypothesis H_proper_task_lock_in_service:
+ proper_task_lock_in_service
+ task_cost job_task arr_seq job_lock_in_service task_lock_in_service tsk.
+
+ (* Consider the EDF policy that indicates a higherorequal priority relation.
+ Note that we do not relate the EDF policy with the scheduler. However, we
+ define functions for Interference and Interfering Workload that actively use
+ the concept of priorities. *)
+ Let EDF: JLFP_policy Job := EDF job_arrival job_relative_deadline.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_pending_at := pending job_arrival job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_backlogged_at := backlogged job_arrival job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let task_scheduled_at := task_scheduled_at job_task sched.
+ Let quiet_time := quiet_time job_arrival job_cost arr_seq sched EDF.
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+ Let cumulative_task_interference :=
+ AbstractSeqRTA.cumul_task_interference job_task arr_seq sched.
+
+ (* We introduce "rbf" as an abbreviation of the task request bound function,
+ which is defined as [task_cost(T) × max_arrivals(T,Δ)] for some task T. *)
+ Let rbf := task_request_bound_function task_cost max_arrivals.
+
+ (* Next, we introduce task_rbf as an abbreviation
+ of the task request bound function of task tsk. *)
+ Let task_rbf := rbf tsk.
+
+ (* Using the sum of individual request bound functions, we define the request bound
+ function of all tasks (total request bound function). *)
+ Let total_rbf := total_request_bound_function task_cost max_arrivals ts.
+
+ (* Assume that there exists a constant priority_inversion_bound that bounds
+ the length of any priority inversion experienced by any job of tsk.
+ Sinse we analyze only task tsk, we ignore the lengths of priority
+ inversions incurred by any other tasks. *)
+ Variable priority_inversion_bound: time.
+ Hypothesis H_priority_inversion_is_bounded:
+ priority_inversion_is_bounded_by
+ job_arrival job_cost job_task arr_seq sched EDF tsk priority_inversion_bound.
+
+ (* Let L be any positive fixed point of the busy interval recurrence. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = priority_inversion_bound + total_rbf L.
+
+ (* Next, we define an upper bound on interfering workload received from jobs
+ of other tasks with higherthanorequal priority. *)
+ Let bound_on_total_hep_workload A Δ :=
+ \sum_(tsk_o < ts  tsk_o != tsk)
+ rbf tsk_o (minn ((A + ε) + D tsk  D tsk_o) Δ).
+
+ (* To reduce the time complexity of the analysis, we introduce the notion of search space for EDF.
+ Intuitively, this corresponds to all "interesting" arrival offsets that the job under
+ analysis might have with regard to the beginning of its busywindow. *)
+
+ (* In case of search space for EDF we ask whether [task_rbf A ≠ task_rbf (A + ε)]... *)
+ Definition task_rbf_changes_at A := task_rbf A != task_rbf (A + ε).
+
+ (* ...or there exists a task tsko from ts such that [tsko ≠ tsk] and
+ [rbf(tsko, A + D tsk  D tsko) ≠ rbf(tsko, A + ε + D tsk  D tsko)].
+ Note that we use a slightly uncommon notation [has (λ tsko ⇒ P tsko) ts]
+ which can be interpreted as follows: taskset ts contains a task tsko such
+ that a predicate P holds for tsko. *)
+ Definition bound_on_total_hep_workload_changes_at A :=
+ has (fun tsko =>
+ (tsk != tsko)
+ && (rbf tsko (A + D tsk  D tsko )
+ != rbf tsko ((A + ε) + D tsk  D tsko))) ts.
+
+ (* The final search space for EDF is a set of offsets that are less than L
+ and where task_rbf or bound_on_total_hep_workload chages. *)
+ Let is_in_search_space A :=
+ (A < L) && (task_rbf_changes_at A  bound_on_total_hep_workload_changes_at A).
+
+ (* Let R be a value that upperbounds the solution of each responsetime recurrence,
+ i.e., for any relative arrival time A in the search space, there exists a corresponding
+ solution F such that [F + (task cost  task lockin service) <= R]. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = priority_inversion_bound
+ + (task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk))
+ + bound_on_total_hep_workload A (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+
+ (* To use the theorem uniprocessor_response_time_bound_seq from the Abstract RTA module,
+ we need to specify functions of interference, interfering workload and IBF. *)
+
+ (* Instantiation of Interference *)
+ (* We say that job j incurs interference at time t iff it cannot execute due to
+ a higherorequalpriority job being scheduled, or if it incurs a priority inversion.
+ (for more details see file limited.limited.jlfp_instantiation.v) *)
+ Let interference (j: Job) (t: time) :=
+ interference sched EDF j t.
+
+ (* Instantiation of Interfering Workload *)
+ (* The interfering workload, in turn, is defined as the sum of the priority inversion
+ function and interfering workload of jobs with higher or equal priority.
+ (for more details see file limited.limited.jlfp_instantiation.v) *)
+ Let interfering_workload (j: Job) (t: time) := interfering_workload job_cost arr_seq sched EDF j t.
+
+ (* Finally, we define the interference bound function as the sum of the priority
+ interference bound and the higherorequalpriority workload. *)
+ Let IBF A R := priority_inversion_bound + bound_on_total_hep_workload A R.
+
+ (** ** Filling Out Hypothesis Of Abstract RTA Theorem *)
+ (** In this section we prove that all hypotheses necessary to use the abstract theorem are satisfied. *)
+ Section FillingOutHypothesesOfAbstractRTATheorem.
+
+ (* First, we prove that in the instantiation of interference and interfering workload,
+ we really take into account everything that can interfere with tsk's jobs, and thus,
+ the scheduler satisfies the abstract notion of work conserving schedule. *)
+ Lemma instantiated_i_and_w_are_coherent_with_schedule:
+ AbstractRTADefinitions.work_conserving
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload.
+ Proof.
+ intros j t1 t2 t ARR TSK POS BUSY NEQ; split; intros HYP.
+ { move: HYP => /negP.
+ rewrite negb_or /is_priority_inversion /BusyIntervalJLFP.is_priority_inversion
+ /is_interference_from_another_job_with_higher_eq_priority.
+ move => /andP [HYP1 HYP2].
+ case SCHED: (sched t) => [s  ].
+ { rewrite SCHED in HYP1, HYP2.
+ move: HYP1 HYP2.
+ rewrite Bool.negb_involutive negb_and.
+ move => HYP1 /orP [/negP HYP2 /eqP HYP2].
+  by exfalso.
+  rewrite Bool.negb_involutive in HYP2.
+ move: HYP2 => /eqP /eqP HYP2.
+ by subst s; rewrite /scheduled_at SCHED.
+ }
+ { exfalso; clear HYP1 HYP2.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval in BUSY; try done; first last.
+ { by rewrite /JLFP_is_reflexive /reflexive /EDF /Priority.EDF. }
+ { by apply job_task. }
+ have EQ:= not_quiet_implies_not_idle
+ job_arrival job_cost arr_seq
+ _ sched EDF j _ _ _ _ _ t1 t2 _ t.
+ feed_n 8 EQ; try done.
+ { by rewrite /JLFP_is_reflexive /reflexive /EDF /Priority.EDF. }
+ { by move: BUSY => [PREF _]. }
+ by eapply EQ; apply/eqP.
+ }
+ }
+ { move: HYP => /eqP HYP.
+ apply/negP; rewrite /interference /JLFPInstantiation.interference /is_priority_inversion
+ /BusyIntervalJLFP.is_priority_inversion
+ /is_interference_from_another_job_with_higher_eq_priority
+ HYP negb_or; apply/andP; split.
+  by rewrite Bool.negb_involutive /EDF /Priority.EDF.
+  by rewrite negb_and Bool.negb_involutive; apply/orP; right.
+ }
+ Qed.
+
+ (* Next, we prove that the interference and interfering workload
+ functions are consistent with sequential jobs. *)
+ Lemma instantiated_interference_and_workload_consistent_with_sequential_jobs:
+ AbstractSeqRTA.interference_and_workload_consistent_with_sequential_jobs
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload.
+ Proof.
+ intros j t1 t2 ARR TSK POS BUSY.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval in BUSY; try done; first last.
+ { by rewrite /JLFP_is_reflexive /reflexive /EDF /Priority.EDF. }
+ { by apply job_task. }
+ eapply all_jobs_have_completed_equiv_workload_eq_service; eauto 2.
+ intros s INs TSKs.
+ rewrite /arrivals_between in INs.
+ move: (INs) => NEQ.
+ eapply in_arrivals_implies_arrived_between in NEQ; eauto 2.
+ move: NEQ => /andP [_ JAs].
+ move: (BUSY) => [[ _ [QT [_ /andP [JAj _]]] _]].
+ apply QT; try done.
+  eapply in_arrivals_implies_arrived; eauto 2.
+  unfold EDF, Priority.EDF.
+ move: TSKs => /eqP TSKs.
+ rewrite /job_relative_deadline TSK TSKs leq_add2r.
+ by apply leq_trans with t1; [apply ltnW  ].
+ Qed.
+
+ (* Recall that L is assumed to be a fixed point of the busy interval recurrence. Thanks to
+ this fact, we can prove that every busy interval (according to the concrete definition)
+ is bounded. In addition, we know that the conventional concept of busy interval and the
+ one obtained from the abstract definition (with the interference and interfering
+ workload) coincide. Thus, it follows that any busy interval (in the abstract sense)
+ is bounded. *)
+ Lemma instantiated_busy_intervals_are_bounded:
+ AbstractRTADefinitions.busy_intervals_are_bounded_by
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload L.
+ Proof.
+ intros j ARR TSK POS.
+ have EX := exists_busy_interval
+ job_arrival job_cost arr_seq _ sched _
+ EDF j _ _ _ _ _ _ priority_inversion_bound _ L.
+ feed_n 12 EX; try eauto 2.
+ { by unfold JLFP_is_reflexive, reflexive, EDF, Priority.EDF. }
+ { intros.
+ rewrite {2}H_fixed_point leq_add //.
+ apply leq_trans with (workload_of_jobs job_cost (jobs_arrived_between arr_seq t (t + L)) predT).
+  rewrite /workload_of_higher_or_equal_priority_jobs /workload_of_jobs
+ big_mkcond [X in _ <= X]big_mkcond leq_sum //=.
+ intros s _.
+ by case (EDF s j).
+  apply total_workload_le_total_rbf'' with job_task; try done.
+ intros tsk0 IN0.
+ by move: (H_family_of_proper_arrival_curves tsk0 IN0) => [ARRB _].
+ }
+ move: EX => [t1 [t2 [H1 [H2 GGG]]]].
+ exists t1, t2; split; first by done.
+ split; first by done.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval; eauto 2.
+ by unfold JLFP_is_reflexive, reflexive, EDF, Priority.EDF.
+ Qed.
+
+ (* Next, we prove that IBF is indeed an interference bound.
+
+ Recall that in module abstract_seq_RTA hypothesis task_interference_is_bounded_by expects
+ to receive a function that maps some task t, the relative arrival time of a job j of task t,
+ and the length of the interval to the maximum amount of interference (for more details see
+ files limited.abstract_RTA.definitions and limited.abstract_RTA.abstract_seq_rta).
+
+ However, in this module we analyze only one task  tsk, therefore it is “hardcoded”
+ inside the interference bound function IBF. Therefore, in order for the IBF signature to
+ match the required signature in module abstract_seq_RTA, we wrap the IBF function in a
+ function that accepts, but simply ignores the task. *)
+ Lemma instantiated_task_interference_is_bounded:
+ AbstractSeqRTA.task_interference_is_bounded_by
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload
+ (fun tsk A R => IBF A R).
+ Proof.
+ clear H_R_is_maximum R.
+ intros j R t1 t2 ARR TSK N NCOMPL BUSY.
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { exfalso.
+ move: NCOMPL => /negP COMPL; apply: COMPL.
+ by rewrite /is_response_time_bound_of_job /completed_by ZERO.
+ }
+ move: (BUSY) => [[/andP [JINBI JINBI2] [QT _]] _].
+ set (A := job_arrival j  t1) in *.
+ have L2 := JLFPInstantiation.cumulative_task_interference_split
+ job_arrival job_cost job_task arr_seq sched _ EDF _ tsk
+ j.
+ rewrite L2; first last; try done.
+ { by eapply arrived_between_implies_in_arrivals; eauto. }
+ { by unfold EDF, job_relative_deadline; eapply EDF_respects_sequential_jobs; eauto. }
+ rewrite /I leq_add //.
+ { unfold priority_inversion_is_bounded_by in *.
+ apply leq_trans with (cumulative_priority_inversion sched EDF j t1 t2).
+ { rewrite [X in _ <= X](@big_cat_nat _ _ _ (t1 + R)) //=.
+  by rewrite leq_addr.
+  by rewrite /is_priority_inversion leq_addr.
+  by rewrite ltnW.
+ }
+ { apply H_priority_inversion_is_bounded; try done.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval in BUSY; try done.
+ { by move: BUSY => [PREF _]. }
+ { by apply job_task. }
+ { by rewrite /JLFP_is_reflexive /reflexive /EDF /Priority.EDF. }
+ }
+ }
+ { rewrite
+ (instantiated_cumulative_interference_of_hep_tasks_equal_total_interference_of_hep_tasks
+ job_arrival job_cost _ arr_seq
+ ); try done; first last.
+ rewrite instantiated_quiet_time_equivalent_edf_quiet_time //.
+ { by apply job_task. }
+ { by rewrite /JLFP_is_reflexive /reflexive /EDF /Priority.EDF. }
+ apply leq_trans with
+ (workload_of_jobs job_cost (arrivals_between t1 (t1 + R))
+ (fun jhp : Job => EDF jhp j && (job_task jhp != job_task j))).
+ { apply service_of_jobs_le_workload; try done. }
+ { rewrite /bound_on_total_hep_workload /rbf /total_ohep_request_bound_function_FP
+ /task_request_bound_function
+ /workload_of_jobs /arrivals_between.
+ set l := jobs_arrived_between arr_seq t1 (t1 + R).
+ apply leq_trans with
+ (\sum_(tsk_o < ts  tsk_o != tsk)
+ (\sum_(j0 < l  EDF j0 j && (job_task j0 == tsk_o)) job_cost j0)).
+ { intros.
+ have EXCHANGE := exchange_big_dep (fun j0 => EDF j0 j && (job_task j0 != job_task j)).
+ rewrite EXCHANGE /=; last first.
+ { move => tsko jo /negP NEQ /andP [EQ1 /eqP EQ2].
+ rewrite EQ1 Bool.andb_true_l; apply/negP; intros CONTR.
+ apply: NEQ; clear EQ1.
+ by rewrite TSK EQ2.
+ }
+ rewrite /workload_of_jobs /l big_seq_cond [X in _ <= X]big_seq_cond.
+ apply leq_sum; move => jo /andP [ARRo /andP [HEQ TSKo]].
+ rewrite (big_rem (job_task jo)) //=.
+ rewrite HEQ eq_refl TSK TSKo andTb andTb leq_addr //.
+ eapply H_all_jobs_from_taskset, in_arrivals_implies_arrived; eauto 2.
+ }
+ apply leq_sum_seq; intros tsko INtsko NEQT.
+ case NEQ: (R <= job_arrival j  t1 + ε + task_deadline tsk  task_deadline tsko).
+ { move: (NEQ) => /minn_idPl => MIN.
+ rewrite minnC in MIN; rewrite MIN; clear MIN.
+ apply leq_trans with (task_cost tsko * num_arrivals_of_task job_task arr_seq tsko t1 (t1 + R)).
+ { apply leq_trans with (\sum_(j0 < l  job_task j0 == tsko) job_cost j0).
+ { rewrite big_mkcond [X in _ <= X]big_mkcond //= leq_sum //.
+ by intros s _; case (job_task s == tsko); case (EDF s j). }
+ { rewrite /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /l /workload_of_jobs.
+ rewrite /is_job_of_task muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ rewrite EQ.
+ apply H_job_cost_le_task_cost.
+ by apply in_arrivals_implies_arrived in IN0.
+ }
+ }
+ { rewrite leq_mul2l; apply/orP; right.
+ rewrite {2}[R](addKn t1).
+ move: (H_family_of_proper_arrival_curves tsko INtsko) => [ARRB _].
+ by apply ARRB; rewrite leq_addr.
+ }
+ }
+ { apply negbT in NEQ; rewrite ltnNge in NEQ; apply ltnW in NEQ.
+ move: (NEQ) => /minn_idPr => MIN.
+ rewrite minnC in MIN; rewrite MIN; clear MIN.
+ set (V := job_arrival j  t1 + ε + task_deadline tsk  task_deadline tsko) in *.
+ apply leq_trans with (task_cost tsko * num_arrivals_of_task job_task arr_seq tsko t1 (t1 + V)).
+ { unfold l.
+ apply leq_trans with
+ (\sum_(jo < jobs_arrived_between arr_seq t1 (t1 + V)  EDF jo j && (job_task jo == tsko))
+ job_cost jo).
+ { rewrite (job_arrived_between_cat _ _ (t1 + V)); [ rewrite leq_addr //rewrite leq_add2l //].
+ rewrite big_cat //=.
+ rewrite [X in _ <= X]addn0 leq_add2l leqn0.
+ rewrite big_seq_cond.
+ apply/eqP; apply big_pred0.
+ intros jo; apply/negP; intros CONTR.
+ move: CONTR => /andP [ARRIN /andP [HEP /eqP TSKo]].
+ unfold EDF, Priority.EDF in HEP.
+ eapply in_arrivals_implies_arrived_between in ARRIN; eauto 2.
+ move: ARRIN => /andP [ARRIN _]; unfold V in ARRIN.
+ have EQ1: job_relative_deadline jo = task_deadline tsko;
+ first by rewrite /job_relative_deadline TSKo.
+ rewrite EQ1 in HEP; clear EQ1.
+ have EQ2: job_relative_deadline j = task_deadline tsk;
+ first by rewrite /job_relative_deadline TSK.
+ rewrite EQ2 in HEP; clear EQ2.
+ case NEQ2: (task_deadline tsko <= job_arrival j  t1 + ε + task_deadline tsk).
+ { move: ARRIN; rewrite leqNgt; move => /negP ARRIN; apply: ARRIN.
+ rewrite (ltn_add2r (task_deadline tsko)).
+ apply leq_ltn_trans with (job_arrival j + task_deadline tsk); first by done.
+ rewrite addnBA; last by done.
+ rewrite addnA addnA.
+ rewrite subnKC; last by done.
+ rewrite subnK.
+  by rewrite ltn_add2r addn1.
+  apply leq_trans with (job_arrival j  t1 + ε + task_deadline tsk); first by done.
+ by rewrite !leq_add2r leq_subr.
+ }
+ { apply negbT in NEQ2; rewrite ltnNge in NEQ2.
+ move: HEP; rewrite leqNgt; move => /negP HEP; apply: HEP.
+ apply leq_ltn_trans with (job_arrival jo + (job_arrival j  t1 + task_deadline tsk)).
+ { rewrite subh1; last by done.
+ rewrite addnBA; last apply leq_trans with (job_arrival j); [  by done  by rewrite leq_addr].
+ rewrite [in X in _ <= X]addnC.
+ rewrite addnBA; first by rewrite leq_addr.
+ by apply leq_trans with (t1 + (job_arrival j  t1 + ε + task_deadline tsk  task_deadline tsko)); first rewrite leq_addr.
+ }
+ { rewrite ltn_add2l.
+ apply leq_ltn_trans with (job_arrival j  t1 + ε + task_deadline tsk); last by done.
+ by rewrite leq_add2r leq_addr.
+ }
+ }
+ }
+ {
+ intros.
+ apply leq_trans with
+ (\sum_(jo < jobs_arrived_between arr_seq t1 (t1 + V)  job_task jo == tsko) job_cost jo).
+ { rewrite big_mkcond [X in _ <= X]big_mkcond //=.
+ rewrite leq_sum //; intros s _.
+ by case (EDF s j).
+ }
+ { rewrite /num_arrivals_of_task sum1_size big_distrr /= big_filter.
+ rewrite /is_job_of_task muln1.
+ apply leq_sum_seq; move => j0 IN0 /eqP EQ.
+ rewrite EQ.
+ apply H_job_cost_le_task_cost.
+ by apply in_arrivals_implies_arrived in IN0.
+ }
+ }
+ }
+ { rewrite leq_mul2l; apply/orP; right.
+ rewrite {2}[V](addKn t1).
+ move: (H_family_of_proper_arrival_curves tsko INtsko) => [ARRB _].
+ by apply ARRB; rewrite leq_addr.
+ }
+ }
+ }
+ }
+
+ Qed.
+
+ (* Finally, we show that there exists a solution for the responsetime recurrence. *)
+ Section SolutionOfResponseTimeReccurenceExists.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Given any job j of task tsk that arrives exactly A units after the beginning of
+ the busy interval, the bound of the total interference incurred by j within an
+ interval of length Δ is equal to [task_rbf (A + ε)  task_cost tsk + IBF(A, Δ)]. *)
+ Let total_interference_bound tsk A Δ :=
+ task_rbf (A + ε)  task_cost tsk + IBF A Δ.
+
+ (* Next, consider any A from the search space (in abstract sence). *)
+ Variable A: time.
+ Hypothesis H_A_is_in_abstract_search_space:
+ AbstractRTAReduction.is_in_search_space tsk L total_interference_bound A.
+
+ (* We prove that A is also in the concrete search space. *)
+ Lemma A_is_in_concrete_search_space:
+ is_in_search_space A.
+ Proof.
+ unfold total_interference_bound in *.
+ unfold AbstractRTAReduction.is_in_search_space in H_A_is_in_abstract_search_space.
+ unfold is_in_search_space in H_R_is_maximum.
+ move: H_A_is_in_abstract_search_space => [INSP  [/andP [POSA LTL] [x [LTx INSP2]]]].
+ { subst A.
+ apply/andP; split; first by done.
+ apply/orP; left.
+ unfold task_rbf_changes_at. rewrite neq_ltn; apply/orP; left.
+ rewrite /task_rbf /rbf. erewrite rbf.RBF.task_rbf_0_zero; eauto 2.
+ rewrite add0n /task_rbf.
+ apply leq_trans with (task_cost tsk).
+ + apply leq_trans with (job_cost j); try eauto 2.
+ by rewrite H_job_of_tsk; apply H_job_cost_le_task_cost.
+ + by eapply rbf.RBF.task_rbf_1_ge_task_cost; eauto 2.
+ }
+ { apply/andP; split; first by done.
+ apply/negPn/negP; intros EQ; move: EQ => /eqP EQ.
+ apply INSP2.
+ move: EQ; rewrite negb_or eqb_id Bool.negb_involutive; move => /andP [/eqP EQ1 /hasPn EQ2].
+ unfold task_rbf, rbf in EQ1.
+ rewrite subn1 addn1 prednK; last by done.
+ rewrite /task_rbf /rbf EQ1.
+ apply/eqP; rewrite eqn_add2l eqn_add2l.
+ unfold bound_on_total_hep_workload .
+ have Abs:
+ forall (T: eqType) (xs: seq T) f1 f2 (P: _ > bool),
+ (forall x, x \in xs > P x > f1 x == f2 x) >
+ \sum_(x < xs  P x) f1 x == \sum_(x < xs  P x) f2 x.
+ { clear.
+ intros.
+ rewrite big_seq_cond [X in _ == X]big_seq_cond.
+ rewrite big_mkcond [X in _ == X]big_mkcond //=.
+ rewrite eqn_leq; apply/andP; split; rewrite leq_sum //; intros i _.
+  case IN: (i \in xs); last by done.
+ case Pi: (P i); simpl; last by done.
+ apply H in IN; last by done.
+ by move: IN => /eqP IN; rewrite IN.
+  case IN: (i \in xs); last by done.
+ case Pi: (P i); simpl; last by done.
+ apply H in IN; last by done.
+ by move: IN => /eqP IN; rewrite IN.
+ }
+ apply: Abs; intros tsk_o IN NEQ.
+ rewrite addn1 prednK; last by done.
+ move: (EQ2 tsk_o IN); clear EQ2.
+ rewrite eq_sym NEQ Bool.andb_true_l Bool.negb_involutive; move => /eqP EQ2.
+ case CASE: (A + ε + task_deadline tsk  task_deadline tsk_o <= x).
+ { have F1: minn (A + task_deadline tsk  task_deadline tsk_o) x =
+ A + task_deadline tsk  task_deadline tsk_o.
+ { rewrite minnE.
+ have CASE2: A + task_deadline tsk  task_deadline tsk_o <= x.
+ { apply leq_trans with (A + ε + task_deadline tsk  task_deadline tsk_o).
+  by apply leq_sub2r; rewrite leq_add2r leq_addr.
+  by done.
+ }
+ move: CASE2; rewrite subn_eq0; move => /eqP CASE2; rewrite CASE2.
+ by rewrite subn0.
+ }
+ have F2: minn (A + ε + task_deadline tsk  task_deadline tsk_o) x =
+ A + ε + task_deadline tsk  task_deadline tsk_o.
+ { rewrite minnE.
+ move: CASE; rewrite subn_eq0; move => /eqP CASE; rewrite CASE.
+ by rewrite subn0.
+ }
+ by apply/eqP; rewrite F1 F2.
+ }
+ { move: CASE => /negP /negP; rewrite ltnNge; move => CASE.
+ have F1: minn (A + task_deadline tsk  task_deadline tsk_o) x = x.
+ { rewrite minnE; rewrite subKn //.
+ rewrite (leq_add2r 1) !addn1.
+ rewrite subSn.
+ { rewrite [in X in _ <= X]addn1.
+ by rewrite addnA [_ + 1]addnC addnA.
+ }
+ { intros.
+ have POS := @leq_ltn_trans _ 0 _ _ CASE.
+ feed POS; first by done.
+ by rewrite subn_gt0 addnA [1 + _]addnC addnA addn1 ltnS in POS.
+ }
+ }
+ have F2: minn (A + ε + task_deadline tsk  task_deadline tsk_o) x = x.
+ { by rewrite minnE; rewrite subKn // ltnW. }
+ by apply/eqP; rewrite F1 F2.
+ }
+ }
+ Qed.
+
+ (* Then, there exists solution for responsetime recurrence (in the abstract sense). *)
+ Corollary correct_search_space:
+ exists F,
+ A + F = task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk) + IBF A (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+ Proof.
+ unfold total_interference_bound in *.
+ unfold AbstractRTAReduction.is_in_search_space in H_A_is_in_abstract_search_space.
+ unfold is_in_search_space in H_R_is_maximum.
+ move: (H_R_is_maximum A) => FIX.
+ feed FIX; first by apply A_is_in_concrete_search_space.
+ move: FIX => [F [FIX NEQ]].
+ exists F; split; last by done.
+ apply/eqP; rewrite {1}FIX.
+ by rewrite addnA [_ + priority_inversion_bound]addnC !addnA.
+ Qed.
+
+ End SolutionOfResponseTimeReccurenceExists.
+
+ End FillingOutHypothesesOfAbstractRTATheorem.
+
+ (** ** Final Theorem *)
+ (* Based on the properties established above, we apply the abstract analysis
+ framework to infer that R is a responsetime bound for tsk. *)
+ Theorem uniprocessor_response_time_bound_edf:
+ response_time_bounded_by tsk R.
+ Proof.
+ intros js ARRs TSKs.
+ move: (posnP (job_cost js)) => [ZEROPOS].
+ { by rewrite /is_response_time_bound_of_job /completed_by ZERO. }
+ eapply AbstractSeqRTA.uniprocessor_response_time_bound_seq with
+ (interference0 := interference) (interfering_workload0 := interfering_workload)
+ (task_interference_bound_function := fun tsk A R => IBF A R) (L0 := L); eauto 3.
+  by apply instantiated_i_and_w_are_coherent_with_schedule.
+  by apply instantiated_interference_and_workload_consistent_with_sequential_jobs.
+  by apply instantiated_busy_intervals_are_bounded.
+  by apply instantiated_task_interference_is_bounded.
+  by eapply correct_search_space; eauto 2.
+ Qed.
+
+ End AbstractResponseTimeAnalysisForEDF.
+
+End AbstractRTAforEDFwithArrivalCurves.
\ No newline at end of file
diff git a/model/schedule/uni/limited/fixed_priority/nonpr_reg/concrete_models/response_time_bound.v b/model/schedule/uni/limited/fixed_priority/nonpr_reg/concrete_models/response_time_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..9c75772c1ee124bd7e32096fef6f6595801750d3
 /dev/null
+++ b/model/schedule/uni/limited/fixed_priority/nonpr_reg/concrete_models/response_time_bound.v
@@ 0,0 +1,609 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time.
+Require Import rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.fixed_priority.nonpr_reg.response_time_bound
+ rt.model.schedule.uni.limited.rbf.
+Require Import rt.model.arrival.curves.bounds
+ rt.analysis.uni.arrival_curves.workload_bound.
+Require Import rt.model.schedule.uni.nonpreemptive.schedule
+ rt.model.schedule.uni.limited.platform.limited
+ rt.model.schedule.uni.limited.platform.preemptive
+ rt.model.schedule.uni.limited.platform.nonpreemptive.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * RTA for concrete models *)
+(** In this module we prove the RTA theorems for (1) fully preemptive FP model,
+ (2) fully nonpreemptive FP model, (3) FP with fixed premption points, and
+ (4) FP with floating nonpreemptive regions. *)
+Module RTAforConcreteModels.
+
+ Import Epsilon Job ArrivalCurves TaskArrival Priority UniprocessorSchedule Workload Service
+ ResponseTime MaxArrivalsWorkloadBound LimitedPreemptionPlatform ModelWithLimitedPreemptions
+ RTAforFPwithBoundedNonpreemptiveSegmentsWithArrivalCurves NonpreemptiveSchedule
+ FullyNonPreemptivePlatform FullyPreemptivePlatform.
+
+ Section Analysis.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Consider an arbitrary task set ts. *)
+ Variable ts: list Task.
+
+ (* Assume that all jobs come from the task set... *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* ...and the cost of a job cannot be larger than the task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Next, consider any uniprocessor schedule... *)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* We also assume that the schedule is a workconserving schedule. *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* Assume we have sequential jobs, i.e, jobs from the same
+ task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Consider an FP policy that indicates a higherorequal priority relation,
+ and assume that the relation is reflexive and transitive. *)
+ Variable higher_eq_priority: FP_policy Task.
+ Hypothesis H_priority_is_reflexive: FP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: FP_is_transitive higher_eq_priority.
+
+ (* Let's define some local names for clarity. *)
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+ Let task_rbf := task_request_bound_function task_cost max_arrivals tsk.
+ Let total_hep_rbf :=
+ total_hep_request_bound_function_FP task_cost higher_eq_priority max_arrivals ts tsk.
+ Let total_ohep_rbf :=
+ total_ohep_request_bound_function_FP task_cost higher_eq_priority max_arrivals ts tsk.
+
+ (** * RTA for fully preemptive FP model *)
+ (** In this module we prove the RTA theorem for fully preemptive FP model *)
+ Section RTAforFullyPreemptiveFPModelwithArrivalCurves.
+
+ (* First, we assume that the schedule respects the FP policy under a fully preemptive model. *)
+ Hypothesis H_respects_policy:
+ respects_FP_policy_at_preemption_point
+ job_arrival job_cost job_task arr_seq sched
+ (can_be_preempted_for_fully_preemptive_model) higher_eq_priority.
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = total_hep_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A := (A < L) && (task_rbf A != task_rbf (A + ε)).
+
+ (* Next, consider any value R, and assume that for any given arrival A from search space
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = task_rbf (A + ε) + total_ohep_rbf (A + F) /\
+ F <= R.
+
+ (* Now, we can leverage the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model of fully preemptive scheduling. *)
+ Theorem uniprocessor_response_time_bound_fully_preemptive_fp:
+ response_time_bounded_by tsk R.
+ Proof.
+ have BLOCK: RTAforFPwithBoundedNonpreemptiveSegmentsWithArrivalCurves.blocking_bound (fun _ => ε) higher_eq_priority ts tsk = 0.
+ { by rewrite /RTAforFPwithBoundedNonpreemptiveSegmentsWithArrivalCurves.blocking_bound subnn big1_eq. }
+ eapply uniprocessor_response_time_bound_fp_with_bounded_nonpreemptive_segments with
+ (task_max_nps := fun _ => ε)
+ (can_be_preempted := fun j prog => true)
+ (task_lock_in_service := fun tsk => task_cost tsk)
+ (job_lock_in_service := fun j => job_cost j)
+ (job_max_nps := fun j => ε); eauto 2; try done.
+  by eapply fully_preemptive_model_is_model_with_bounded_nonpreemptive_regions.
+  repeat split; try done.
+ intros ? ? ? ARR; move => LE COMPL /negP NCOMPL.
+ exfalso; apply: NCOMPL.
+ apply completion_monotonic with t; try done.
+  repeat split; try done.
+ rewrite /task_lock_in_service_le_task_cost. by done.
+ unfold task_lock_in_service_bounds_job_lock_in_service.
+ by intros ? ARR TSK; rewrite TSK; apply H_job_cost_le_task_cost.
+  by rewrite BLOCK add0n.
+  move => A /andP [LT NEQ].
+ specialize (H_R_is_maximum A); feed H_R_is_maximum.
+ { by apply/andP; split. }
+ move: H_R_is_maximum => [F [FIX BOUND]].
+ exists F; split.
+ + by rewrite BLOCK add0n subnn subn0.
+ + by rewrite subnn addn0.
+ Qed.
+
+ End RTAforFullyPreemptiveFPModelwithArrivalCurves.
+
+ (** * RTA for fully nonpreemptive FP model *)
+ (** In this module we prove the RTA theorem for the fully nonpreemptive FP model. *)
+ Section RTAforFullyNonPreemptiveFPModelwithArrivalCurves.
+
+ (* First, assume that the schedule is nonpreemptive... *)
+ Hypothesis H_nonpreemptive_sched: is_nonpreemptive_schedule job_cost sched.
+
+ (* ... which respects the FP policy under a fully nonpreemptive model. *)
+ Hypothesis H_respects_policy:
+ respects_FP_policy_at_preemption_point
+ job_arrival job_cost job_task arr_seq sched
+ (can_be_preempted_for_fully_nonpreemptive_model job_cost) higher_eq_priority.
+
+ (* Next, we define a bound for the priority inversion caused by tasks of lower priority. *)
+ Let blocking_bound :=
+ \max_(tsk_other < ts  ~~ higher_eq_priority tsk_other tsk) (task_cost tsk_other  ε).
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_hep_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A := (A < L) && (task_rbf A != task_rbf (A + ε)).
+
+ (* Next, consider any value R, and assume that for any given arrival A from search space
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound
+ + (task_rbf (A + ε)  (task_cost tsk  ε))
+ + total_ohep_rbf (A + F) /\
+ F + (task_cost tsk  ε) <= R.
+
+ (* Now, we can leverage the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model of fully nonpreemptive scheduling. *)
+ Theorem uniprocessor_response_time_bound_fully_nonpreemptive_fp:
+ response_time_bounded_by tsk R.
+ Proof.
+ move: (posnP (task_cost tsk)) => [ZEROPOS].
+ { intros j ARR TSK.
+ have ZEROj: job_cost j = 0.
+ { move: (H_job_cost_le_task_cost j ARR) => NEQ.
+ rewrite /job_cost_le_task_cost TSK ZERO in NEQ.
+ by apply/eqP; rewrite leqn0.
+ }
+ by rewrite /is_response_time_bound_of_job /completed_by ZEROj.
+ }
+ eapply uniprocessor_response_time_bound_fp_with_bounded_nonpreemptive_segments with
+ (job_max_nps := fun j => job_cost j)
+ (task_max_nps := fun tsk => task_cost tsk)
+ (job_lock_in_service := fun j => ε)
+ (task_lock_in_service := fun tsk => ε)
+ (L0 := L); eauto 2.
+  by eapply fully_nonpreemptive_model_is_correct; eauto 2.
+  eapply fully_nonpreemptive_model_is_model_with_bounded_nonpreemptive_regions; eauto 2.
+  repeat split; try done.
+  intros j t t' ARR LE SERV NCOMPL.
+ rewrite /service in SERV; apply incremental_service_during in SERV.
+ move: SERV => [t_first [/andP [_ H1] [H2 H3]]].
+ apply H_nonpreemptive_sched with t_first; try done.
+ by apply leq_trans with t; first apply ltnW.
+  repeat split; try done.
+ Qed.
+
+ End RTAforFullyNonPreemptiveFPModelwithArrivalCurves.
+
+ (** * RTA for FPschedulers with fixed premption points *)
+ (** In this module we prove a general RTA theorem for FPschedulers with fixed preemption points *)
+ Section RTAforFixedPreemptionPointsModelwithArrivalCurves.
+
+ (* First, we assume we have the model with fixed preemption points.
+ I.e., each task is divided into a number of nonpreemptive segments
+ by inserting staticaly predefined preemption points. *)
+ Variable job_preemption_points: Job > seq time.
+ Variable task_preemption_points: Task > seq time.
+ Hypothesis H_model_with_fixed_preemption_points:
+ fixed_preemption_points_model
+ task_cost job_cost job_task arr_seq
+ job_preemption_points task_preemption_points ts.
+
+ (* Next, assume that the schedule is a schedule with limited preemptions... *)
+ Hypothesis H_schedule_with_limited_preemptions:
+ is_schedule_with_limited_preemptions arr_seq job_preemption_points sched.
+
+ (* ... which respects the FP policy under a model with fixed preemption points. *)
+ Hypothesis H_respects_policy:
+ respects_FP_policy_at_preemption_point
+ job_arrival job_cost job_task arr_seq sched
+ (can_be_preempted_for_model_with_limited_preemptions job_preemption_points) higher_eq_priority.
+
+ (* We also have a set of functions that map job or task
+ to its max or last nonpreemptive segment. *)
+ Let job_max_nps := job_max_nps job_preemption_points.
+ Let job_last_nps := job_last_nps job_preemption_points.
+ Let task_max_nps := task_max_nps task_preemption_points.
+ Let task_last_nps := task_last_nps task_preemption_points.
+
+ (* Next, we define a bound for the priority inversion caused by tasks of lower priority. *)
+ Let blocking_bound :=
+ \max_(tsk_other < ts  ~~ higher_eq_priority tsk_other tsk) (task_max_nps tsk_other  ε).
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_hep_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A := (A < L) && (task_rbf A != task_rbf (A + ε)).
+
+ (* Next, consider any value R, and assume that for any given arrival A from search space
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound
+ + (task_rbf (A + ε)  (task_last_nps tsk  ε))
+ + total_ohep_rbf (A + F) /\
+ F + (task_last_nps tsk  ε) <= R.
+
+ (* Now, we can reuse the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model of fixed preemption points. *)
+ Theorem uniprocessor_response_time_bound_fp_with_fixed_preemption_points:
+ response_time_bounded_by tsk R.
+ Proof.
+ move: (H_model_with_fixed_preemption_points) => [MLP [BEG [END [INCR [HYP1 [HYP2 HYP3]]]]]].
+ move: (MLP) => [EMPTj [LSMj [BEGj [ENDj HH]]]].
+ move: (posnP (task_cost tsk)) => [ZEROPOSt].
+ { intros j ARR TSK.
+ move: (H_job_cost_le_task_cost _ ARR) => POSt.
+ move: POSt; rewrite /job_cost_le_task_cost TSK ZERO leqn0; move => /eqP Z.
+ by rewrite /is_response_time_bound_of_job /completed_by Z.
+ }
+ have Fact2: 1 < size (task_preemption_points tsk).
+ { have Fact2: 0 < size (task_preemption_points tsk).
+ { apply/negPn/negP; rewrite eqn0Ngt; intros CONTR; move: CONTR => /eqP CONTR.
+ move: (END _ H_tsk_in_ts) => EQ.
+ move: EQ; rewrite /NondecreasingSequence.last nth_last nth_default; last by rewrite CONTR.
+ by intros; rewrite EQ in POSt.
+ }
+ have EQ: 2 = size [::0; task_cost tsk]; first by done.
+ rewrite EQ; clear EQ.
+ apply subseq_leq_size.
+ rewrite !cons_uniq.
+ { apply/andP; split.
+ rewrite in_cons negb_or; apply/andP; split; last by done.
+ rewrite neq_ltn; apply/orP; left; eauto 2.
+ apply/andP; split; by done. }
+ intros t EQ; move: EQ; rewrite !in_cons.
+ move => /orP [/eqP EQ /orP [/eqP EQEQ]]; last by done.
+ { rewrite EQ; clear EQ.
+ move: (BEG _ H_tsk_in_ts) => EQ.
+ rewrite EQ; clear EQ.
+ rewrite /NondecreasingSequence.first nth0.
+ apply/(nthP 0).
+ exists 0; by done.
+ }
+ { rewrite EQ; clear EQ.
+ move: (END _ H_tsk_in_ts) => EQ.
+ rewrite EQ; clear EQ.
+ rewrite /NondecreasingSequence.last nth_last.
+ apply/(nthP 0).
+ exists ((size (task_preemption_points tsk)).1); last by done.
+ by rewrite (leq_add2r 1) !addn1 prednK //.
+ }
+ }
+ eapply uniprocessor_response_time_bound_fp_with_bounded_nonpreemptive_segments
+ with (task_lock_in_service := fun tsk => (task_cost tsk  (task_last_nps tsk  ε)))
+ (job_lock_in_service := fun job => (job_cost job  (job_last_nps job  ε)))
+ (L0 := L) (job_max_nps0 := job_max_nps)
+ (job_cost0 := job_cost )
+ ; eauto 2.
+ { by apply model_with_fixed_preemption_points_is_correct. }
+ {
+ eapply model_with_fixed_preemption_points_is_model_with_bounded_nonpreemptive_regions; eauto 2.
+ intros j ARR.
+ unfold ModelWithLimitedPreemptions.job_max_nps, task_max_nps, lengths_of_segments.
+ apply NondecreasingSequence.max_of_dominating_seq.
+ intros. apply HYP2.
+ by done.
+ }
+ { split; last split.
+ { intros j ARR POS.
+ rewrite subn_gt0.
+ rewrite subn1 (leq_add2r 1) !addn1 prednK; last first.
+ apply LSMj; try done.
+ rewrite /job_last_nps /ModelWithLimitedPreemptions.job_last_nps
+ ltnS /NondecreasingSequence.last nth_last NondecreasingSequence.function_of_distances_is_correct.
+ apply leq_trans with (job_max_nps j);
+ first by apply NondecreasingSequence.distance_between_neighboring_elements_le_max_distance_in_seq.
+ rewrite ENDj; last by done.
+ by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ { by intros j ARR; rewrite leq_subLR leq_addl. }
+ { intros ? ? ? ARR LE LS NCOMPL.
+ rewrite subnBA in LS; last first.
+ apply LSMj; try done.
+ { rewrite lt0n; apply/negP; intros Z; move: Z => /eqP Z.
+ by move: NCOMPL; rewrite /completed_by ltnNge Z ltn0. }
+ have EQ: exists Δ, t' = t + Δ.
+ { exists (t'  t); rewrite subnKC; by done. }
+ move: EQ => [Δ EQ]; subst t'; clear LE.
+ rewrite subh1 in LS.
+ rewrite addn1 in LS.
+ apply H_schedule_with_limited_preemptions; first by done.
+ rewrite /can_be_preempted_for_model_with_limited_preemptions; apply/negP.
+ intros CONTR.
+ move: NCOMPL; rewrite /completed_by ltnNge; move => SERV.
+ have NEQ: job_cost j  job_last_nps j < service sched j (t + Δ).
+ { apply leq_trans with (service sched j t); first by done.
+ rewrite /service /service_during [in X in _ <= X](@big_cat_nat _ _ _ t) //=.
+ rewrite leq_addr //.
+ rewrite leq_addr //.
+ }
+ clear LS.
+ rewrite ENDj in NEQ, SERV; last by done.
+ rewrite NondecreasingSequence.last_seq_minus_last_distance_seq in NEQ; last by eauto 2.
+ rewrite /NondecreasingSequence.last nth_last in SERV.
+ have EQ := NondecreasingSequence.antidensity_of_nondecreasing_seq.
+ specialize (EQ (job_preemption_points j) (service sched j (t + Δ)) (size (job_preemption_points j)).2).
+ rewrite CONTR in EQ.
+ feed_n 2 EQ; first by eauto 2.
+ {
+ apply/andP; split; first by done.
+ rewrite prednK; first by done.
+ rewrite (leq_add2r 1) !addn1 prednK.
+ eapply number_of_preemption_points_at_least_two with (job_cost0 := job_cost); eauto 2.
+ eapply list_of_preemption_point_is_not_empty with (job_cost0 := job_cost); eauto 2.
+ }
+ by done.
+
+ rewrite ENDj; last by done.
+ apply leq_trans with (job_max_nps j).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ }
+ {
+ split.
+  by rewrite /task_lock_in_service_le_task_cost leq_subLR leq_addl.
+  intros j ARR TSK.
+ move: (posnP (job_cost j)) => [ZERO  POS].
+ { by rewrite ZERO. }
+ unfold task_last_nps.
+ rewrite !subnBA; first last.
+ apply LSMj; try done.
+ rewrite /ModelWithLimitedPreemptions.task_last_nps /NondecreasingSequence.last nth_last.
+ apply HYP3.
+ by done.
+ rewrite (ltn_add2r 1) !addn1 prednK //.
+ move: (Fact2) => Fact3.
+ rewrite NondecreasingSequence.size_of_seq_of_distances // addn1 ltnS // in Fact2.
+ rewrite subh1 ?[in X in _ <= X]subh1; first last.
+ { apply leq_trans with (job_max_nps j).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by rewrite ENDj //; apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ { apply leq_trans with (task_max_nps tsk).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by rewrite END //; apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ rewrite ENDj; last eauto 2.
+ rewrite END; last eauto 2.
+ rewrite !NondecreasingSequence.last_seq_minus_last_distance_seq.
+ have EQ: size (job_preemption_points j) = size (task_preemption_points tsk).
+ { rewrite TSK.
+ by apply HYP1.
+ }
+ rewrite EQ; clear EQ.
+ rewrite leq_add2r.
+ apply NondecreasingSequence.domination_of_distances_implies_domination_of_seq; try done; eauto 2.
+ rewrite BEG // BEGj //.
+ eapply number_of_preemption_points_at_least_two with (job_cost0 := job_cost); eauto 2.
+ rewrite TSK; apply HYP1; try done.
+ intros. rewrite TSK; eauto 2.
+ eauto 2.
+ eauto 2.
+ }
+ { rewrite subKn; first by done.
+ rewrite /task_last_nps (leq_add2r 1) subn1 !addn1 prednK; last first.
+ { rewrite /ModelWithLimitedPreemptions.task_last_nps /NondecreasingSequence.last nth_last.
+ apply HYP3; try by done.
+ rewrite (ltn_add2r 1) !addn1 prednK //.
+ move: (Fact2) => Fact3.
+ by rewrite NondecreasingSequence.size_of_seq_of_distances // addn1 ltnS // in Fact2.
+ }
+ { apply leq_trans with (task_max_nps tsk).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  rewrite END; last by done.
+ apply ltnW; rewrite ltnS; try done.
+ by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ }
+ Qed.
+
+ End RTAforFixedPreemptionPointsModelwithArrivalCurves.
+
+ (** * RTA for FPschedulers with floating nonpreemptive regions *)
+ (** In this module we prove a general RTA theorem for FPschedulers with floating nonpreemptive regions *)
+ Section RTAforModelWithFloatingNonpreemptiveRegionsWithArrivalCurves.
+
+ (* Assume we have the model with floating nonpreemptive regions.
+ I.e., for each task only the length of the maximal nonpreemptive
+ segment is known. *)
+ Variable job_preemption_points: Job > seq time.
+ Variable task_max_nps: Task > time.
+ Hypothesis H_task_model_with_floating_nonpreemptive_regions:
+ model_with_floating_nonpreemptive_regions
+ job_cost job_task arr_seq job_preemption_points task_max_nps.
+
+ (* Next, assume that the schedule is a schedule with limited preemptions... *)
+ Hypothesis H_schedule_with_limited_preemptions:
+ is_schedule_with_limited_preemptions arr_seq job_preemption_points sched.
+
+ (* ... which respects the FP policy under a model with fixed preemption points. *)
+ Hypothesis H_respects_policy:
+ respects_FP_policy_at_preemption_point
+ job_arrival job_cost job_task arr_seq sched
+ (can_be_preempted_for_model_with_limited_preemptions job_preemption_points) higher_eq_priority.
+
+ (* Let's define some local names for clarity. *)
+ Let job_max_nps := job_max_nps job_preemption_points.
+ Let job_last_nps := job_last_nps job_preemption_points.
+
+ (* Next, we define a bound for the priority inversion caused by tasks of lower priority. *)
+ Let blocking_bound :=
+ \max_(tsk_other < ts  ~~ higher_eq_priority tsk_other tsk) (task_max_nps tsk_other  ε).
+
+ (* Let L be any positive fixed point of the busy interval recurrence, determined by
+ the sum of blocking and higherorequalpriority workload. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_hep_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A := (A < L) && (task_rbf A != task_rbf (A + ε)).
+
+ (* Next, consider any value R, and assume that for any given arrival A from search space
+ there is a solution of the responsetime bound recurrence which is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound + task_rbf (A + ε) + total_ohep_rbf (A + F) /\
+ F <= R.
+
+ (* Now, we can reuse the results for the abstract model with bounded nonpreemptive segments
+ to establish a responsetime bound for the more concrete model with floating nonpreemptive regions. *)
+ Theorem uniprocessor_response_time_bound_fp_with_floating_nonpreemptive_regions:
+ response_time_bounded_by tsk R.
+ Proof.
+ move: (H_task_model_with_floating_nonpreemptive_regions) => [LIMJ JMLETM].
+ move: (LIMJ) => [ZERO [LSMj [BEG [END HH]]]].
+ eapply uniprocessor_response_time_bound_fp_with_bounded_nonpreemptive_segments
+ with (task_lock_in_service := fun tsk => task_cost tsk)
+ (job_lock_in_service := fun job => (job_cost job  (job_last_nps job  ε)))
+ (L0 := L) (job_max_nps0 := job_max_nps)
+ (job_cost0 := job_cost )
+ ; eauto 2.
+ { by apply model_with_fixed_preemption_points_is_correct. }
+ { by eapply model_with_fixed_preemption_points_is_model_with_bounded_nonpreemptive_regions; eauto 2. }
+ { split; last split.
+ { intros j ARR POS.
+ rewrite subn_gt0.
+ rewrite subn1 (leq_add2r 1) !addn1 prednK; last first.
+ apply LSMj; try done.
+ rewrite /job_last_nps /ModelWithLimitedPreemptions.job_last_nps
+ ltnS /NondecreasingSequence.last nth_last NondecreasingSequence.function_of_distances_is_correct.
+ apply leq_trans with (job_max_nps j); first by apply NondecreasingSequence.distance_between_neighboring_elements_le_max_distance_in_seq.
+ rewrite END; last by done.
+ by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ { by intros j ARR; rewrite leq_subLR leq_addl. }
+ { intros ? ? ? ARR LE LS NCOMPL.
+ rewrite subnBA in LS; last first.
+ apply LSMj; try done.
+ { rewrite lt0n; apply/negP; intros Z; move: Z => /eqP Z.
+ by move: NCOMPL; rewrite /completed_by ltnNge Z ltn0. }
+ have EQ: exists Δ, t' = t + Δ.
+ { exists (t'  t); rewrite subnKC; by done. }
+ move: EQ => [Δ EQ]; subst t'; clear LE.
+ rewrite subh1 in LS.
+ rewrite addn1 in LS.
+ apply H_schedule_with_limited_preemptions; first by done.
+ rewrite /can_be_preempted_for_model_with_limited_preemptions; apply/negP.
+ intros CONTR.
+ move: NCOMPL; rewrite /completed_by ltnNge; move => SERV.
+ have NEQ: job_cost j  (job_last_nps j) < service sched j (t + Δ).
+ { apply leq_trans with (service sched j t); first by done.
+ rewrite /service /service_during [in X in _ <= X](@big_cat_nat _ _ _ t) //=.
+ rewrite leq_addr //.
+ rewrite leq_addr //.
+ }
+ clear LS.
+ rewrite END in NEQ, SERV; last by done.
+ rewrite NondecreasingSequence.last_seq_minus_last_distance_seq in NEQ.
+ rewrite /NondecreasingSequence.last nth_last in SERV.
+ have EQ := NondecreasingSequence.antidensity_of_nondecreasing_seq.
+ specialize (EQ (job_preemption_points j) (service sched j (t + Δ)) (size (job_preemption_points j)).2).
+ rewrite CONTR in EQ.
+ feed_n 2 EQ; first by eauto 2.
+ {
+ apply/andP; split; first by done.
+ rewrite prednK; first by done.
+ rewrite (leq_add2r 1) !addn1 prednK.
+ eapply number_of_preemption_points_at_least_two with (job_cost0 := job_cost); eauto 2.
+ eapply list_of_preemption_point_is_not_empty with (job_cost0 := job_cost); eauto 2.
+ }
+ by done.
+ eauto 2.
+
+ rewrite END; last by done.
+ apply leq_trans with (job_max_nps j).
+  by apply NondecreasingSequence.last_of_seq_le_max_of_seq.
+  by apply NondecreasingSequence.max_distance_in_seq_le_last_element_of_seq; eauto 2.
+ }
+ }
+ {
+ split.
+  by rewrite /task_lock_in_service_le_task_cost.
+  intros j ARR TSK.
+ apply leq_trans with (job_cost j); first by rewrite leq_subr.
+ by rewrite TSK; eauto 2.
+ }
+ {
+ rewrite subnn.
+ intros.
+ apply H_R_is_maximum in H.
+ move: H => [F [EQ LE]].
+ exists F.
+ by rewrite subn0 addn0; split.
+ }
+ Qed.
+
+ End RTAforModelWithFloatingNonpreemptiveRegionsWithArrivalCurves.
+
+ End Analysis.
+
+End RTAforConcreteModels.
\ No newline at end of file
diff git a/model/schedule/uni/limited/fixed_priority/nonpr_reg/response_time_bound.v b/model/schedule/uni/limited/fixed_priority/nonpr_reg/response_time_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..1d917819387d09eea134ff5d1ec2c674c7fe9505
 /dev/null
+++ b/model/schedule/uni/limited/fixed_priority/nonpr_reg/response_time_bound.v
@@ 0,0 +1,292 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.arrival.curves.bounds
+ rt.analysis.uni.arrival_curves.workload_bound.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time.
+Require Import rt.model.schedule.uni.limited.platform.definitions
+ rt.model.schedule.uni.limited.platform.priority_inversion_is_bounded
+ rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.busy_interval
+ rt.model.schedule.uni.limited.fixed_priority.response_time_bound
+ rt.model.schedule.uni.limited.rbf.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * RTA for FPschedulers with bounded nonpreemptive segments *)
+(** In this module we prove a general RTA theorem for FPschedulers *)
+Module RTAforFPwithBoundedNonpreemptiveSegmentsWithArrivalCurves.
+
+ Import Epsilon Job ArrivalCurves TaskArrival Priority UniprocessorSchedule Workload Service
+ ResponseTime MaxArrivalsWorkloadBound LimitedPreemptionPlatform RBF
+ AbstractRTAforFPwithArrivalCurves BusyIntervalJLFP PriorityInversionIsBounded.
+
+ Section Analysis.
+
+ Context {Task: eqType}.
+ Variable task_max_nps task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_max_nps job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Assume we have sequential jobs, i.e, jobs from the same
+ task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Assume that a job cost cannot be larger than a task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Consider an FP policy that indicates a higherorequal priority relation,
+ and assume that the relation is reflexive and transitive. *)
+ Variable higher_eq_priority: FP_policy Task.
+ Hypothesis H_priority_is_reflexive: FP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: FP_is_transitive higher_eq_priority.
+
+ (* We consider an arbitrary function can_be_preempted which defines
+ a preemption model with bounded nonpreemptive segments. *)
+ Variable can_be_preempted: Job > time > bool.
+ Let preemption_time := preemption_time sched can_be_preempted.
+ Hypothesis H_correct_preemption_model:
+ correct_preemption_model arr_seq sched can_be_preempted.
+ Hypothesis H_model_with_bounded_nonpreemptive_segments:
+ model_with_bounded_nonpreemptive_segments
+ job_cost job_task arr_seq can_be_preempted job_max_nps task_max_nps.
+
+ (* Next, we assume that the schedule is a workconserving schedule... *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* ... and the schedule respects the policy defined by the
+ can_be_preempted function (i.e., bounded nonpreemptive segments). *)
+ Hypothesis H_respects_policy:
+ respects_FP_policy_at_preemption_point
+ job_arrival job_cost job_task arr_seq sched can_be_preempted higher_eq_priority.
+
+ (* Consider an arbitrary task set ts... *)
+ Variable ts: list Task.
+
+ (* ..and assume that all jobs come from the task set. *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Consider a proper job lockin service and task lockin functions, i.e... *)
+ Variable job_lock_in_service: Job > time.
+ Variable task_lock_in_service: Task > time.
+
+ (* ...we assume that for all jobs in the arrival sequence the lockin service is
+ (1) positive, (2) no bigger than costs of the corresponding jobs, and (3) a job
+ becomes nonpreemptive after it reaches its lockin service... *)
+ Hypothesis H_proper_job_lock_in_service:
+ proper_job_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* ...and that [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any
+ job of task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Hypothesis H_proper_task_lock_in_service:
+ proper_task_lock_in_service
+ task_cost job_task arr_seq job_lock_in_service task_lock_in_service tsk.
+
+ (* We also lift the FP priority relation to a corresponding JLFP priority relation. *)
+ Let jlfp_higher_eq_priority := FP_to_JLFP job_task higher_eq_priority.
+
+ (* Let's define some local names for clarity. *)
+ Let job_pending_at := pending job_arrival job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_backlogged_at := backlogged job_arrival job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let max_length_of_priority_inversion :=
+ max_length_of_priority_inversion job_max_nps arr_seq jlfp_higher_eq_priority.
+ Let response_time_bounded_by :=
+ is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+ Let task_rbf := task_request_bound_function task_cost max_arrivals tsk.
+ Let total_hep_rbf :=
+ total_hep_request_bound_function_FP task_cost higher_eq_priority max_arrivals ts tsk.
+ Let total_ohep_rbf :=
+ total_ohep_request_bound_function_FP task_cost higher_eq_priority max_arrivals ts tsk.
+
+ (* We also define a bound for the priority inversion caused by jobs with lower priority. *)
+ Definition blocking_bound :=
+ \max_(tsk_other < ts  ~~ higher_eq_priority tsk_other tsk)
+ (task_max_nps tsk_other  ε).
+
+ (** ** Priority inversion is bounded *)
+ (** In this section, we prove that a priority inversion for task tsk is bounded by
+ the maximum length of nonpreemtive segments among the tasks with lower priority. *)
+ Section PriorityInversionIsBounded.
+
+ (* First, we prove that the maximum length of a priority inversion of a job j is
+ bounded by the maximum length of a nonpreemptive section of a task with
+ lowerpriority task (i.e., the blocking term). *)
+ Lemma priority_inversion_is_bounded_by_blocking:
+ forall j t,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ max_length_of_priority_inversion j t <= blocking_bound.
+ Proof.
+ intros j t ARR TSK.
+ rewrite /max_length_of_priority_inversion
+ /PriorityInversionIsBounded.max_length_of_priority_inversion
+ /blocking_bound /jlfp_higher_eq_priority /FP_to_JLFP.
+ apply leq_trans with
+ (\max_(j_lp < jobs_arrived_between arr_seq 0 t
+  ~~ higher_eq_priority (job_task j_lp) tsk)
+ (task_max_nps (job_task j_lp)  ε)
+ ).
+ { rewrite TSK.
+ apply leq_big_max.
+ intros j' JINB NOTHEP.
+ specialize (H_job_cost_le_task_cost j').
+ feed H_job_cost_le_task_cost.
+ { apply mem_bigcat_nat_exists in JINB.
+ by move: JINB => [ta' [JIN' _]]; exists ta'.
+ }
+ rewrite leq_sub2r //.
+ apply in_arrivals_implies_arrived in JINB.
+ move: (H_model_with_bounded_nonpreemptive_segments j' JINB) => [_ [_ [T _]]].
+ by apply T.
+ }
+ { apply /bigmax_leq_seqP.
+ intros j' JINB NOTHEP.
+ apply leq_bigmax_cond_seq with
+ (i0 := (job_task j')) (F := fun tsk => task_max_nps tsk  1); last by done.
+ apply H_all_jobs_from_taskset.
+ apply mem_bigcat_nat_exists in JINB.
+ by inversion JINB as [ta' [JIN' _]]; exists ta'.
+ }
+ Qed.
+
+ (* Using the above lemma, we prove that the priority inversion of the task is bounded by blocking_bound. *)
+ Lemma priority_inversion_is_bounded:
+ priority_inversion_is_bounded_by
+ job_arrival job_cost job_task arr_seq sched jlfp_higher_eq_priority tsk blocking_bound.
+ Proof.
+ intros j ARR TSK POS t1 t2 PREF.
+ case NEQ: (t2  t1 <= blocking_bound).
+ { apply leq_trans with (t2  t1); last by done.
+ rewrite /cumulative_priority_inversion /BusyIntervalJLFP.is_priority_inversion.
+ rewrite [X in _ <= X]addn0 [t2  t1]mul1n iter_addn big_const_nat.
+ rewrite leq_sum //.
+ intros t _; case: (sched t); last by done.
+ by intros s; case: jlfp_higher_eq_priority.
+ }
+ move: NEQ => /negP /negP; rewrite ltnNge; move => NEQ.
+ have PPE := preemption_time_exists
+ task_max_nps job_arrival job_max_nps job_cost job_task arr_seq _ sched
+ _ _ _ jlfp_higher_eq_priority _ _ can_be_preempted
+ _ _ _ _ j ARR _ t1 t2 PREF .
+ feed_n 11 PPE; try done.
+ { unfold JLFP_is_reflexive, jlfp_higher_eq_priority, FP_to_JLFP. by done. }
+ { unfold JLFP_is_transitive, jlfp_higher_eq_priority, FP_to_JLFP, transitive. eauto 2. }
+ move: PPE => [ppt [PPT /andP [GE LE]]].
+ apply leq_trans with (cumulative_priority_inversion sched jlfp_higher_eq_priority j t1 ppt);
+ last apply leq_trans with (ppt  t1).
+  rewrite /cumulative_priority_inversion /BusyIntervalJLFP.is_priority_inversion.
+ rewrite (@big_cat_nat _ _ _ ppt) //=.
+ rewrite [X in _ <= X]addn0 leq_add2l.
+ rewrite leqn0.
+ rewrite big_nat_cond big1 //; move => t /andP [/andP [GEt LTt] _ ].
+ case SCHED: (sched t) => [s  ]; last by done.
+ have SCHEDHP := not_quiet_implies_exists_scheduled_hp_job
+ task_max_nps job_arrival job_max_nps job_cost job_task arr_seq _ sched
+ _ _ _ jlfp_higher_eq_priority _ _ can_be_preempted
+ _ _ _ _ j ARR _ t1 t2 _ (ppt  t1) _ t.
+ feed_n 14 SCHEDHP; try done.
+ { unfold JLFP_is_reflexive, jlfp_higher_eq_priority, FP_to_JLFP. by done. }
+ { unfold JLFP_is_transitive, jlfp_higher_eq_priority, FP_to_JLFP, transitive. eauto 2. }
+ { exists ppt; split. by done. by rewrite subnKC //; apply/andP; split. }
+ { by rewrite subnKC //; apply/andP; split. }
+ move: SCHEDHP => [j_hp [ARRB [HP SCHEDHP]]].
+ apply/eqP; rewrite eqb0 Bool.negb_involutive.
+ have EQ: s = j_hp.
+ { by apply only_one_job_scheduled with (sched0 := sched) (t0 := t); [apply/eqP  ]. }
+ by rewrite EQ.
+ rewrite ltn_subRL in NEQ.
+ apply leq_trans with (t1 + blocking_bound); last by apply ltnW.
+ apply leq_trans with (t1 + max_length_of_priority_inversion j t1); first by done.
+ rewrite leq_add2l; eapply priority_inversion_is_bounded_by_blocking; eauto 2.
+  rewrite /cumulative_priority_inversion /BusyIntervalJLFP.is_priority_inversion.
+ rewrite [X in _ <= X]addn0 [ppt  t1]mul1n iter_addn big_const_nat.
+ rewrite leq_sum //.
+ intros t _; case: (sched t); last by done.
+ by intros s; case: jlfp_higher_eq_priority.
+  rewrite leq_subLR.
+ apply leq_trans with (t1 + max_length_of_priority_inversion j t1); first by done.
+ rewrite leq_add2l; eapply priority_inversion_is_bounded_by_blocking; eauto 2.
+ Qed.
+
+ End PriorityInversionIsBounded.
+
+ (** ** ResponseTime Bound *)
+ (** In this section, we prove that the maximum among the solutions of the responsetime
+ bound recurrence is a responsetime bound for tsk. *)
+ Section ResponseTimeBound.
+
+ (* Let L be any positive fixed point of the busy interval recurrence. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = blocking_bound + total_hep_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space. *)
+ Let is_in_search_space A := (A < L) && (task_rbf A != task_rbf (A + ε)).
+
+ (* Next, consider any value R, and assume that for any given arrival offset A from the search
+ space there is a solution of the responsetime bound recurrence that is bounded by R. *)
+ Variable R: nat.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = blocking_bound
+ + (task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk))
+ + total_ohep_rbf (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+ (* Then, using the results for the general RTA for FPschedulers, we establish a
+ responsetime bound for the more concrete model of bounded nonpreemptive segments.
+ Note that in case of the general RTA for FPschedulers, we just _assume_ that
+ the priority inversion is bounded. In this module we provide the preemption model
+ with bounded nonpreemptive segments and _prove_ that the priority inversion is
+ bounded. *)
+ Theorem uniprocessor_response_time_bound_fp_with_bounded_nonpreemptive_segments:
+ response_time_bounded_by tsk R.
+ Proof.
+ eapply uniprocessor_response_time_bound_fp; eauto 2.
+ by apply priority_inversion_is_bounded.
+ Qed.
+
+ End ResponseTimeBound.
+
+ End Analysis.
+
+End RTAforFPwithBoundedNonpreemptiveSegmentsWithArrivalCurves.
\ No newline at end of file
diff git a/model/schedule/uni/limited/fixed_priority/response_time_bound.v b/model/schedule/uni/limited/fixed_priority/response_time_bound.v
new file mode 100644
index 0000000000000000000000000000000000000000..58c43350a70a77c60e44881c4f9c63e8d1c7ccc5
 /dev/null
+++ b/model/schedule/uni/limited/fixed_priority/response_time_bound.v
@@ 0,0 +1,436 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.response_time
+ rt.model.schedule.uni.schedule_of_task.
+Require Import rt.model.schedule.uni.limited.platform.definitions
+ rt.model.schedule.uni.limited.schedule
+ rt.model.schedule.uni.limited.rbf
+ rt.model.schedule.uni.limited.abstract_RTA.definitions
+ rt.model.schedule.uni.limited.abstract_RTA.reduction_of_search_space
+ rt.model.schedule.uni.limited.abstract_RTA.abstract_seq_rta
+ rt.model.schedule.uni.limited.jlfp_instantiation.
+Require Import rt.model.arrival.curves.bounds.
+Require Import rt.analysis.uni.arrival_curves.workload_bound.
+Require Import rt.model.schedule.uni.limited.busy_interval.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Abstract RTA for FPschedulers *)
+(** In this module we propose the abstract responsetime analysis (RTA) for
+ FP uniprocessor scheduling of realtime tasks with arbitrary arrival models. *)
+Module AbstractRTAforFPwithArrivalCurves.
+
+ Import Epsilon Job ArrivalCurves TaskArrival Priority ScheduleOfTask
+ UniprocessorSchedule Workload Service ResponseTime MaxArrivalsWorkloadBound
+ LimitedPreemptionPlatform RBF BusyIntervalJLFP JLFPInstantiation.
+
+ Section AbstractResponseTimeAnalysisForFP.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Next, assume that the schedule is a workconserving schedule. *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* Assume we have sequential jobs, i.e, jobs from the
+ same task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Assume that a job cost cannot be larger than a task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* Consider an arbitrary task set ts. *)
+ Variable ts: list Task.
+
+ (* Next, we assume that all jobs come from the task set. *)
+ Hypothesis H_all_jobs_from_taskset:
+ forall j, arrives_in arr_seq j > job_task j \in ts.
+
+ (* Let max_arrivals be a family of proper arrival curves, i.e., for any task tsk in ts
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is a monotonic function
+ that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_family_of_proper_arrival_curves:
+ family_of_proper_arrival_curves job_task arr_seq max_arrivals ts.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+ Hypothesis H_tsk_in_ts: tsk \in ts.
+
+ (* Consider proper job lockin service and task lockin functions, i.e... *)
+ Variable job_lock_in_service: Job > time.
+ Variable task_lock_in_service: Task > time.
+
+ (* ...we assume that for all jobs with positive cost in the arrival sequence the
+ lockin service is (1) positive, (2) no bigger than costs of the corresponding
+ jobs, and (3) a job becomes nonpreemptive after it reaches its lockin service... *)
+ Hypothesis H_proper_job_lock_in_service:
+ proper_job_lock_in_service job_cost arr_seq sched job_lock_in_service.
+
+ (* ...and that [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any
+ job of task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Hypothesis H_proper_task_lock_in_service:
+ proper_task_lock_in_service
+ task_cost job_task arr_seq job_lock_in_service task_lock_in_service tsk.
+
+ (* Consider an FP policy that indicates a higherorequal priority relation,
+ and assume that the relation is reflexive. Note that we do not relate
+ the FP policy with the scheduler. However, we define functions for
+ Interference and Interfering Workload that actively use the concept of
+ priorities. We require the FP policy to be reflexive, so a job cannot
+ cause lowerpriority interference (i.e. priority inversion) to itself. *)
+ Variable higher_eq_priority: FP_policy Task.
+ Hypothesis H_priority_is_reflexive: FP_is_reflexive higher_eq_priority.
+
+ (* We also lift the FP priority relation to a corresponding JLFP priority relation. *)
+ Let jlfp_higher_eq_priority j1 j2 := FP_to_JLFP job_task higher_eq_priority j1 j2.
+
+ (* For clarity, let's define some local names. *)
+ Let job_pending_at := pending job_arrival job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_backlogged_at := backlogged job_arrival job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let response_time_bounded_by := is_response_time_bound_of_task job_arrival job_cost job_task arr_seq sched.
+ Let quiet_time := quiet_time job_arrival job_cost arr_seq sched jlfp_higher_eq_priority.
+ Let busy_interval := busy_interval job_arrival job_cost arr_seq sched jlfp_higher_eq_priority.
+ Let task_scheduled_at := task_scheduled_at job_task sched.
+ Let cumulative_task_interference :=
+ AbstractSeqRTA.cumul_task_interference job_task arr_seq sched.
+
+ (* We introduce task_rbf as an abbreviation of the task request bound function,
+ which is defined as [task_cost(tsk) × max_arrivals(tsk,Δ)]. *)
+ Let task_rbf := task_request_bound_function task_cost max_arrivals tsk.
+
+ (* Using the sum of individual request bound functions, we define the request bound
+ function of all tasks with higherorequal priority (with respect to tsk). *)
+ Let total_hep_rbf :=
+ total_hep_request_bound_function_FP task_cost higher_eq_priority max_arrivals ts tsk.
+
+ (* Similarly, we define the request bound function of all tasks other
+ than tsk with higherorequal priority (with respect to tsk). *)
+ Let total_ohep_rbf :=
+ total_ohep_request_bound_function_FP task_cost higher_eq_priority max_arrivals ts tsk.
+
+ (* Assume that there eixsts a constant priority_inversion_bound that bounds
+ the length of any priority inversion experienced by any job of tsk.
+ Sinse we analyze only task tsk, we ignore the lengths of priority
+ inversions incurred by any other tasks. *)
+ Variable priority_inversion_bound: time.
+ Hypothesis H_priority_inversion_is_bounded:
+ priority_inversion_is_bounded_by
+ job_arrival job_cost job_task arr_seq sched jlfp_higher_eq_priority tsk priority_inversion_bound.
+
+ (* Let L be any positive fixed point of the busy interval recurrence. *)
+ Variable L: time.
+ Hypothesis H_L_positive: L > 0.
+ Hypothesis H_fixed_point: L = priority_inversion_bound + total_hep_rbf L.
+
+ (* To reduce the time complexity of the analysis, recall the notion of search space.
+ Intuitively, this corresponds to all "interesting" arrival offsets that the job under
+ analysis might have with regard to the beginning of its busywindow. *)
+ Let is_in_search_space A := (A < L) && (task_rbf A != task_rbf (A + ε)).
+
+ (* Let R be a value that upperbounds the solution of each responsetime recurrence,
+ i.e., for any relative arrival time A in the search space, there exists a corresponding
+ solution F such that [F + (task cost  task lockin service) <= R]. *)
+ Variable R: time.
+ Hypothesis H_R_is_maximum:
+ forall A,
+ is_in_search_space A >
+ exists F,
+ A + F = priority_inversion_bound
+ + (task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk))
+ + total_ohep_rbf (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+
+
+ (* Instantiation of Interference *)
+ (* We say that job j incurs interference at time t iff it cannot execute due to
+ a higherorequalpriority job being scheduled, or if it incurs a priority inversion.
+ (for more details see file limited.jlfp_instantiation.v) *)
+ Let interference (j: Job) (t: time) :=
+ interference sched jlfp_higher_eq_priority j t.
+
+ (* Instantiation of Interfering Workload *)
+ (* The interfering workload, in turn, is defined as the sum of the priority inversion
+ function and interfering workload of jobs with higher or equal priority.
+ (for more details see file limited.limited.jlfp_instantiation.v) *)
+ Let interfering_workload (j: Job) (t: time) :=
+ interfering_workload job_cost arr_seq sched jlfp_higher_eq_priority j t.
+
+ (* Finally, we define the interference bound function as the sum of the priority
+ interference bound and the higherorequalpriority workload. *)
+ Let IBF R := priority_inversion_bound + total_ohep_rbf R.
+
+ (** ** Filling Out Hypotheses Of Abstract RTA Theorem *)
+ (** In this section we prove that all preconditions necessary to use the abstract theorem are satisfied. *)
+ Section FillingOutHypothesesOfAbstractRTATheorem.
+
+ (* First, we prove that in the instantiation of interference and interfering workload,
+ we really take into account everything that can interfere with tsk's jobs, and thus,
+ the scheduler satisfies the abstract notion of work conserving schedule. *)
+ Lemma instantiated_i_and_w_are_consistent_with_schedule:
+ AbstractRTADefinitions.work_conserving
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload.
+ Proof.
+ intros j t1 t2 t ARR TSK POS BUSY NEQ; split; intros HYP.
+ unfold AbstractRTADefinitions.busy_interval, AbstractRTADefinitions.busy_interval_prefix in *.
+ { move: HYP => /negP.
+ rewrite negb_or /is_priority_inversion /BusyIntervalJLFP.is_priority_inversion
+ /is_interference_from_another_job_with_higher_eq_priority.
+ move => /andP [HYP1 HYP2].
+ case SCHED: (sched t) => [s  ].
+ { rewrite SCHED in HYP1, HYP2.
+ move: HYP1 HYP2.
+ rewrite !Bool.negb_involutive negb_and Bool.negb_involutive.
+ move => HYP1 /orP [/negP HYP2 /eqP HYP2].
+  by exfalso.
+  by subst s; rewrite /scheduled_at SCHED.
+ }
+ { exfalso; clear HYP1 HYP2.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval in BUSY; try done; first last.
+ { by intros x; apply H_priority_is_reflexive. }
+ { by apply job_task. }
+ have EQ:= not_quiet_implies_not_idle
+ job_arrival job_cost arr_seq _
+ sched jlfp_higher_eq_priority j _ _ _ _ _ t1 t2 _ t.
+ feed_n 8 EQ; try done.
+  by rewrite /jlfp_higher_eq_priority /JLFP_is_reflexive /FP_to_JLFP.
+  by move: BUSY => [PREF _].
+  by apply EQ; apply/eqP.
+ }
+ }
+ { move: HYP => /eqP HYP.
+ apply/negP.
+ rewrite /interference /JLFPInstantiation.interference /is_priority_inversion
+ /BusyIntervalJLFP.is_priority_inversion
+ /jlfp_higher_eq_priority /is_interference_from_another_job_with_higher_eq_priority HYP negb_or.
+ apply/andP; split.
+  by rewrite Bool.negb_involutive /FP_to_JLFP.
+  by rewrite negb_and Bool.negb_involutive; apply/orP; right.
+ }
+ Qed.
+
+ (* Next, we prove that the interference and interfering workload
+ functions are consistent with sequential jobs. *)
+ Lemma instantiated_interference_and_workload_consistent_with_sequential_jobs:
+ AbstractSeqRTA.interference_and_workload_consistent_with_sequential_jobs
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload.
+ Proof.
+ intros j t1 t2 ARR TSK POS BUSY.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval in BUSY; first last; try by done.
+ { by intros x; apply H_priority_is_reflexive. }
+ { by apply job_task. }
+ eapply all_jobs_have_completed_equiv_workload_eq_service; eauto 2; intros s ARRs TSKs.
+ move: (BUSY) => [[_ [QT _]] _].
+ apply QT.
+  by apply in_arrivals_implies_arrived in ARRs.
+  move: TSKs => /eqP TSKs.
+ by rewrite /jlfp_higher_eq_priority /FP_to_JLFP TSK TSKs.
+  by eapply in_arrivals_implies_arrived_before; eauto 2.
+ Qed.
+
+ (* Recall that L is assumed to be a fixed point of the busy interval recurrence. Thanks to
+ this fact, we can prove that every busy interval (according to the concrete definition)
+ is bounded. In addition, we know that the conventional concept of busy interval and the
+ one obtained from the abstract definition (with the interference and interfering
+ workload) coincide. Thus, it follows that any busy interval (in the abstract sense)
+ is bounded. *)
+ Lemma instantiated_busy_intervals_are_bounded:
+ AbstractRTADefinitions.busy_intervals_are_bounded_by
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload L.
+ Proof.
+ intros j ARR TSK POS.
+ have EX := exists_busy_interval
+ job_arrival job_cost arr_seq _ sched _
+ jlfp_higher_eq_priority j _ _ _ _ _ _ priority_inversion_bound _ L.
+ feed_n 12 EX; try eauto 2.
+ { by rewrite /JLFP_is_reflexive /jlfp_higher_eq_priority /FP_to_JLFP. }
+ { intros.
+ rewrite {2}H_fixed_point leq_add //.
+ apply total_workload_le_total_rbf'; try done.
+ by intros tsko INo; move: (H_family_of_proper_arrival_curves tsko INo) => [ARRB _].
+ }
+ move: EX => [t1 [t2 [H1 [H2 GGG]]]].
+ exists t1, t2; split; first by done.
+ split; first by done.
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval; eauto 2.
+ by intros x; apply H_priority_is_reflexive.
+ Qed.
+
+ (* Next, we prove that IBF is indeed an interference bound.
+
+ Recall that in module abstract_seq_RTA hypothesis task_interference_is_bounded_by expects
+ to receive a function that maps some task t, the relative arrival time of a job j of task t,
+ and the length of the interval to the maximum amount of interference (for more details see
+ files limited.abstract_RTA.definitions and limited.abstract_RTA.abstract_seq_rta).
+
+ However, in this module we analyze only one task  tsk, therefore it is “hardcoded”
+ inside the interference bound function IBF. Moreover, in case of a model with fixed
+ priorities, interference that some job j incurs from higherorequal priority jobs does not
+ depend on the relative arrival time of job j. Therefore, in order for the IBF signature to
+ match the required signature in module abstract_seq_RTA, we wrap the IBF function in a
+ function that accepts, but simply ignores, the task and the relative arrival time. *)
+ Lemma instantiated_task_interference_is_bounded:
+ AbstractSeqRTA.task_interference_is_bounded_by
+ job_arrival job_cost job_task arr_seq sched tsk interference interfering_workload
+ (fun t A R => IBF R).
+ Proof.
+ intros ? ? ? ? ARR TSK ? NCOMPL BUSY.
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { exfalso.
+ move: NCOMPL => /negP COMPL; apply: COMPL.
+ by rewrite /is_response_time_bound_of_job /completed_by ZERO.
+ }
+ eapply instantiated_busy_interval_equivalent_edf_busy_interval in BUSY; first last; try done.
+ { by intros x; apply H_priority_is_reflexive. }
+ { by apply job_task. }
+ have T123 := cumulative_task_interference_split.
+ rewrite /cumulative_task_interference in T123.
+ rewrite (T123 _ _ job_arrival job_cost _ _ _ _ _ _ _ j); eauto 2; last first.
+ { move: BUSY => [[_ [_ [_ /andP [GE LT]]]] _].
+ by eapply arrived_between_implies_in_arrivals; eauto 2. }
+ { by apply any_reflexive_FP_respects_sequential_jobs. }
+ unfold IBF, interference.
+ rewrite leq_add; try done.
+ { unfold is_priority_inversion, FP_to_JLFP.
+ unfold priority_inversion_is_bounded_by in *.
+ move: (H_priority_inversion_is_bounded j ARR TSK) => BOUND.
+ apply leq_trans with (cumulative_priority_inversion sched jlfp_higher_eq_priority j t1 (t1 + R0)).
+ { by done. }
+ { apply leq_trans with (cumulative_priority_inversion sched jlfp_higher_eq_priority j t1 t2).
+ { rewrite [X in _ <= X](@big_cat_nat _ _ _ (t1 + R0)) //=.
+  by rewrite leq_addr.
+  by rewrite leq_addr.
+  by rewrite ltnW.
+ }
+ { by apply BOUND; move: BUSY => [PREF QT2]. }
+ }
+ }
+ { intros.
+ rewrite
+ (instantiated_cumulative_interference_of_hep_tasks_equal_total_interference_of_hep_tasks
+ job_arrival job_cost _ arr_seq); last first; try done.
+ { by unfold quiet_time; move: BUSY => [[_ [H1 H2]] _]. }
+ apply leq_trans with
+ (workload_of_jobs
+ job_cost (arrivals_between t1 (t1 + R0))
+ (fun jhp : Job => jlfp_higher_eq_priority jhp j && (job_task jhp != job_task j))).
+ { by apply service_of_jobs_le_workload. }
+ { rewrite /workload_of_jobs
+ /total_ohep_rbf /total_ohep_request_bound_function_FP.
+ rewrite TSK; apply total_workload_le_total_rbf; try done.
+ by intros tsko INo; move: (H_family_of_proper_arrival_curves tsko INo) => [ARRB _].
+ }
+ }
+ Qed.
+
+ (* Finally, we show that there exists a solution for the responsetime recurrence. *)
+ Section SolutionOfResponseTimeReccurenceExists.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Given any job j of task tsk that arrives exactly A units after the beginning of
+ the busy interval, the bound of the total interference incurred by j within an
+ interval of length Δ is equal to [task_rbf (A + ε)  task_cost tsk + IBF Δ]. *)
+ Let total_interference_bound tsk A Δ :=
+ task_rbf (A + ε)  task_cost tsk + IBF Δ.
+
+ (* Next, consider any A from the search space (in the abstract sence). *)
+ Variable A: time.
+ Hypothesis H_A_is_in_abstract_search_space:
+ AbstractRTAReduction.is_in_search_space tsk L total_interference_bound A.
+
+ (* We prove that A is also in the concrete search space. *)
+ Lemma A_is_in_concrete_search_space:
+ is_in_search_space A.
+ Proof.
+ unfold total_interference_bound in *.
+ move: H_A_is_in_abstract_search_space => [INSP  [/andP [POSA LTL] [x [LTx INSP2]]]].
+  rewrite INSP.
+ apply/andP; split; first by done.
+ rewrite neq_ltn; apply/orP; left.
+ rewrite {1}/task_rbf; erewrite rbf.RBF.task_rbf_0_zero; eauto 2; try done.
+ rewrite add0n /task_rbf.
+ apply leq_trans with (task_cost tsk).
+ + by apply leq_trans with (job_cost j); rewrite ?H_job_of_tsk; eauto 2.
+ + by eapply rbf.RBF.task_rbf_1_ge_task_cost; eauto 2.
+  apply/andP; split; first by done.
+ apply/negP; intros EQ; move: EQ => /eqP EQ.
+ apply INSP2.
+ rewrite subn1 addn1 prednK; last by done.
+ by rewrite EQ.
+ Qed.
+
+ (* Then, there exists a solution for the responsetime recurrence (in the abstract sense). *)
+ Corollary correct_search_space:
+ exists F,
+ A + F = task_rbf (A + ε)  (task_cost tsk  task_lock_in_service tsk) + IBF (A + F) /\
+ F + (task_cost tsk  task_lock_in_service tsk) <= R.
+ Proof.
+ move: (H_R_is_maximum A) => FIX.
+ feed FIX; first by apply A_is_in_concrete_search_space.
+ move: FIX => [F [FIX NEQ]].
+ exists F; split; last by done.
+ apply/eqP; rewrite {1}FIX.
+ by rewrite addnA [_ + priority_inversion_bound]addnC !addnA.
+ Qed.
+
+ End SolutionOfResponseTimeReccurenceExists.
+
+ End FillingOutHypothesesOfAbstractRTATheorem.
+
+ (** ** Final Theorem *)
+ (* Based on the properties established above, we apply the abstract analysis
+ framework to infer that R is a responsetime bound for tsk. *)
+ Theorem uniprocessor_response_time_bound_fp:
+ response_time_bounded_by tsk R.
+ Proof.
+ intros js ARRs TSKs.
+ move: (posnP (job_cost js)) => [ZEROPOS].
+ { by rewrite /is_response_time_bound_of_job /completed_by ZERO. }
+ move: H_proper_job_lock_in_service => [T1 [T2 T3]].
+ move: H_proper_task_lock_in_service => [T4 T5].
+ eapply AbstractSeqRTA.uniprocessor_response_time_bound_seq with
+ (interference0 := interference) (interfering_workload0 := interfering_workload)
+ (task_interference_bound_function := fun _ A R => IBF R) (L0 := L) (ts0 := ts); eauto 3.
+  by apply instantiated_i_and_w_are_consistent_with_schedule.
+  by apply instantiated_interference_and_workload_consistent_with_sequential_jobs.
+  by apply instantiated_busy_intervals_are_bounded.
+  by apply instantiated_task_interference_is_bounded.
+  by eapply correct_search_space; eauto 2.
+ Qed.
+
+ End AbstractResponseTimeAnalysisForFP.
+
+End AbstractRTAforFPwithArrivalCurves.
\ No newline at end of file
diff git a/model/schedule/uni/limited/jlfp_instantiation.v b/model/schedule/uni/limited/jlfp_instantiation.v
new file mode 100644
index 0000000000000000000000000000000000000000..53df179d7494d69aff509eac4e16029a02acf7c0
 /dev/null
+++ b/model/schedule/uni/limited/jlfp_instantiation.v
@@ 0,0 +1,763 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.workload
+ rt.model.schedule.uni.schedule_of_task.
+Require Import rt.model.schedule.uni.limited.busy_interval
+ rt.model.schedule.uni.limited.abstract_RTA.definitions
+ rt.model.schedule.uni.limited.abstract_RTA.abstract_seq_rta.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * JLFP instantiation of Interference and Interfering Workload *)
+(** In this module we instantiate functions Interference and Interfering Workload
+ for an arbitrary JLFPpolicy that satisfies the sequential jobs hypothesis.
+ We also prove equivalence of Interference and Interfering Workload to the
+ more conventional notions of service or workload. *)
+Module JLFPInstantiation.
+
+ Import Job TaskArrival ScheduleOfTask Priority Workload Service BusyIntervalJLFP.
+
+ Section Instantiation.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Assume we have sequential jobs, i.e., jobs from the
+ same task execute in the order of their arrival. *)
+ Hypothesis H_sequential_jobs: sequential_jobs job_arrival job_cost sched job_task.
+
+ (* Consider a JLFPpolicy that indicates a higherorequal priority relation,
+ and assume that this relation is reflexive and transitive. *)
+ Variable higher_eq_priority: JLFP_policy Job.
+ Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.
+
+ (* We also assume that the policy respects sequential jobs, meaning
+ that laterarrived jobs of a task don't have higher priority than
+ earlierarrived jobs of the same task. *)
+ Hypothesis H_JLFP_respects_sequential_jobs:
+ JLFP_respects_sequential_jobs
+ job_task job_arrival higher_eq_priority.
+
+ (* Let tsk be any task in ts that is to be analyzed. *)
+ Variable tsk: Task.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+ Let quiet_time := quiet_time job_arrival job_cost arr_seq sched higher_eq_priority.
+ Let cumulative_task_interference :=
+ AbstractSeqRTA.cumul_task_interference job_task arr_seq sched.
+
+ (** ** Interference and Interfering Workload *)
+ (** In this section, we introduce definitions of interference,
+ interfering workload and a function that bounds cumulative interference. *)
+
+ (* For proper calculation of interference and interfering workload of a job, we need to distinguish
+ interference received from other jobs of the same task and other jobs of other tasks. In that
+ regard, we introduce two additional relations. The first relation defines whether job j1 has a
+ higherthanorequalpriority than job j2 and j1 is not equal to j2... *)
+ Let another_job_with_higher_eq_priority: JLFP_policy Job :=
+ fun j1 j2 => higher_eq_priority j1 j2 && (j1 != j2).
+
+ (* ...and the second relation defines whether a job j1 has a higherorequalpriority than
+ job j2 and the task of j1 is not equal to task of j2. *)
+ Let job_from_another_task_with_higher_eq_priority: JLFP_policy Job :=
+ fun j1 j2 => higher_eq_priority j1 j2 && (job_task j1 != job_task j2).
+
+ (* In order to introduce the interference, first we need to recall the definition
+ of priority inversion introduced in module limited.fixed_priority.busy_interval:
+ [ Definition is_priority_inversion t := ]
+ [ if sched t is Some jlp then ]
+ [ ~~ higher_eq_priority jlp j ]
+ [ else false. ]
+ I.e., we say that job j is incurring a priority inversion at time t
+ if there exists a job with lower priority that executes at time t.
+ In order to simplify things, we ignore the fact that according to this
+ definition a job can incur priority inversion even before its release
+ (or after completion). All such (potentially bad) cases do not cause
+ problems, as each job is analyzed only within the corresponding busy
+ interval where the priority inversion behaves in the expected way. *)
+ Let is_priority_inversion (j: Job) (t: time) :=
+ is_priority_inversion sched higher_eq_priority j t.
+
+ (* Next, we say that job j is incurring interference from another job with higher or equal
+ priority at time t, if there exists job jhp (different from j) with a higher or equal priority
+ that executes at time t. *)
+ Definition is_interference_from_another_job_with_higher_eq_priority (j: Job) (t: time) :=
+ if sched t is Some jhp then
+ another_job_with_higher_eq_priority jhp j
+ else false.
+
+ (* Similarly, we say that job j is incurring interference from a job with higher or
+ equal priority of another task at time t, if there exists a job jhp (of a different task)
+ with higher or equal priority that executes at time t. *)
+ Definition is_interference_from_another_task_with_higher_eq_priority (j: Job) (t: time) :=
+ if sched t is Some jhp then
+ job_from_another_task_with_higher_eq_priority jhp j
+ else false.
+
+ (* Now, we define the notion of cumulative interference, called
+ interfering_workload_of_jobs_with_hep_priority, that says
+ how many units of workload are generated by jobs with higher
+ or equal priority released at time t. *)
+ Definition interfering_workload_of_jobs_with_hep_priority (j: Job) (t: time) :=
+ \sum_(jhp < jobs_arriving_at arr_seq t 
+ another_job_with_higher_eq_priority jhp j) job_cost jhp.
+
+ (* Instantiation of Interference *)
+ (* We say that job j incurs interference at time t iff it cannot execute due to
+ a higherorequalpriority job being scheduled, or if it incurs a priority inversion. *)
+ Definition interference j t :=
+ is_priority_inversion j t  is_interference_from_another_job_with_higher_eq_priority j t.
+
+ (* Instantiation of Interfering Workload *)
+ (* The interfering workload, in turn, is defined as the sum of the priority inversion
+ function and interfering workload of jobs with higher or equal priority. *)
+ Definition interfering_workload j t :=
+ is_priority_inversion j t + interfering_workload_of_jobs_with_hep_priority j t.
+
+ (* For each of the concepts defined above, we introduce a corresponding cumulative function: *)
+ (* (a) cumulative priority inversion... *)
+ Let cumulative_priority_inversion j t1 t2 :=
+ \sum_(t1 <= t < t2) is_priority_inversion j t.
+
+ (* ... (b) cumulative interference from other jobs with higher or equal priority... *)
+ Let cumulative_interference_from_other_jobs j t1 t2 :=
+ \sum_(t1 <= t < t2) is_interference_from_another_job_with_higher_eq_priority j t.
+
+ (* ... (c) and cumulative interference from jobs with higher or equal priority from other tasks... *)
+ Let cumulative_interference_from_other_tasks j t1 t2 :=
+ \sum_(t1 <= t < t2) is_interference_from_another_task_with_higher_eq_priority j t.
+
+ (* ... (d) cumulative interference... *)
+ Let cumulative_interference j t1 t2 := \sum_(t1 <= t < t2) interference j t.
+
+ (* ... (e) cumulative workload from jobs with higher or equal priority... *)
+ Let cumulative_interfering_workload_of_jobs_with_hep_priority j t1 t2 :=
+ \sum_(t1 <= t < t2) interfering_workload_of_jobs_with_hep_priority j t.
+
+ (* ... (f) and cumulative interfering workload. *)
+ Let cumulative_interfering_workload j t1 t2 := \sum_(t1 <= t < t2) interfering_workload j t.
+
+ (* Instantiated functions usually do not have any useful lemmas about them. In order to
+ reuse existing lemmas, we need to prove equivalence of the instantiated functions to
+ some conventional notions. The instantiations given in this file are equivalent to
+ service and workload. Further, we prove these equivalences formally. *)
+
+ (* Before we present the formal proofs of the equivalences, we recall
+ the notion of workload of higher or equal priority jobs. *)
+ Let workload_of_other_jobs_with_hep_priority j t1 t2 :=
+ workload_of_jobs job_cost (arrivals_between t1 t2)
+ (fun jhp => another_job_with_higher_eq_priority jhp j).
+
+ (* Similarly, we recall notions of service of higher or equal priority jobs from other tasks... *)
+ Let service_of_jobs_from_other_tasks_with_hep_priority j t1 t2 :=
+ service_of_jobs sched (arrivals_between t1 t2)
+ (fun jhp => job_from_another_task_with_higher_eq_priority jhp j) t1 t2.
+
+ (* ... and service of all other jobs with higher or equal priority. *)
+ Let service_of_other_jobs_with_hep_priority j t1 t2 :=
+ service_of_jobs sched (arrivals_between t1 t2)
+ (fun jhp => another_job_with_higher_eq_priority jhp j) t1 t2.
+
+ (** ** Equivalences *)
+ (** In this section we prove a few equivalences between the definitions obtained by
+ instantiation of definitions from the Abstract RTA module (interference and
+ interfering workload) and definitions corresponding to the conventional concepts.
+
+ As it was mentioned previously, instantiated functions of interference and
+ interfering workload usually do not have any useful lemmas about them. Hovewer,
+ it is possible to prove their equivalence to the more conventional notions like
+ service or workload. Next we prove the equivalence between the instantiations
+ and conventional notions. *)
+ Section Equivalences.
+
+ (* We prove that we can split cumulative interference into two parts: (1) cumulative priority
+ inversion and (2) cumulative interference from jobs with higher or equal priority. *)
+ Lemma cumulative_interference_split:
+ forall j t1 t2,
+ cumulative_interference j t1 t2
+ = cumulative_priority_inversion j t1 t2 + cumulative_interference_from_other_jobs j t1 t2.
+ rewrite /cumulative_interference /cumulative_priority_inversion
+ /cumulative_interference_from_other_jobs /interference.
+ intros; rewrite big_split //=.
+ apply/eqP; rewrite eqn_leq; apply/andP; split; rewrite leq_sum; try done.
+ { intros t _; unfold is_priority_inversion,
+ BusyIntervalJLFP.is_priority_inversion,
+ is_interference_from_another_job_with_higher_eq_priority.
+ case SCHED: (sched t) => [s  ]; last by done.
+ by case HP: (higher_eq_priority s j); simpl; rewrite ?addn0 ?add0n.
+ }
+ { intros t _; unfold is_priority_inversion,
+ BusyIntervalJLFP.is_priority_inversion,
+ is_interference_from_another_job_with_higher_eq_priority.
+ case SCHED: (sched t) => [s  ]; last by done.
+ unfold another_job_with_higher_eq_priority.
+ by case HP: (higher_eq_priority s j); simpl; rewrite ?addn0 ?add0n.
+ }
+ Qed.
+
+ (* Let j be any job of task tsk, and let upp_t be any time instant after job j's arrival.
+ Then for any time interval lying before upp_t, the cumulative interference received by tsk
+ is equal to the sum of the cumulative priority inversion of job j and the cumulative interference
+ incurred by task tsk due to other tasks. *)
+ Lemma cumulative_task_interference_split:
+ forall j t1 t2 upp_t,
+ job_task j = tsk >
+ j \in jobs_arrived_before arr_seq upp_t >
+ ~~ job_completed_by j t2 >
+ cumulative_task_interference interference tsk upp_t t1 t2 =
+ cumulative_priority_inversion j t1 t2 +
+ cumulative_interference_from_other_tasks j t1 t2.
+ Proof.
+ rewrite /cumulative_task_interference /AbstractSeqRTA.cumul_task_interference
+ /ScheduleOfTask.task_scheduled_at
+ /cumulative_priority_inversion
+ /cumulative_interference_from_other_tasks.
+ intros j t1 R upp TSK ARR NCOMPL.
+ rewrite big_split //=.
+ rewrite big_nat_cond [X in _ = X]big_nat_cond.
+ apply/eqP; rewrite eqn_leq; apply/andP; split.
+ { apply leq_sum; intros t _.
+ rewrite /interference /is_priority_inversion /BusyIntervalJLFP.is_priority_inversion
+ /is_interference_from_another_task_with_higher_eq_priority
+ /is_interference_from_another_job_with_higher_eq_priority
+ /AbstractSeqRTA.task_interference_received_before
+ /another_job_with_higher_eq_priority /job_from_another_task_with_higher_eq_priority
+ /ScheduleOfTask.task_scheduled_at.
+ case SCHED: (sched t) => [s  ]; last by rewrite has_pred0 addn0 leqn0 eqb0.
+ case HP: (higher_eq_priority s j); simpl; last by rewrite addn0 leq_b1.
+ rewrite add0n TSK.
+ case: ((job_task s != tsk)); last by done.
+ by rewrite Bool.andb_true_l leq_b1.
+ }
+ { apply leq_sum; move => t /andP [/andP [_ LT'] _].
+ rewrite /is_priority_inversion /BusyIntervalJLFP.is_priority_inversion
+ /is_interference_from_another_task_with_higher_eq_priority
+ /is_interference_from_another_job_with_higher_eq_priority /another_job_with_higher_eq_priority
+ /job_from_another_task_with_higher_eq_priority /AbstractSeqRTA.task_interference_received_before
+ /ScheduleOfTask.task_scheduled_at .
+ case SCHED: (sched t) => [s  ]; last by done.
+ rewrite TSK; case TSKEQ: (job_task s == job_task j); simpl.
+ { rewrite Bool.andb_false_r leqn0 addn0 eqb0.
+ apply/negP; intros NEQ.
+ move: SCHED => /eqP SCHED.
+ move: NCOMPL => /negP NCOMPL; apply: NCOMPL.
+ apply completion_monotonic with t; [ by apply ltnW  ].
+ apply/negP; intros NCOMPL; move: NCOMPL => /negP NCOMPL.
+ have ARRle := (scheduler_executes_job_with_earliest_arrival
+ job_arrival _ _ _ _ s j t TSKEQ NCOMPL SCHED).
+ feed ARRle; try done.
+ move: NEQ => /negP NEQ; apply: NEQ.
+ by apply H_JLFP_respects_sequential_jobs.
+ }
+ have NEQ: s != j.
+ { apply/negP; intros EQ; move: EQ => /eqP EQ.
+ move: TSKEQ => /eqP TSKEQ; apply: TSKEQ.
+ by rewrite EQ.
+ }
+ have Fact: forall b, ~~ b + b = true; first by intros b; destruct b.
+ rewrite Bool.andb_true_r Fact; simpl; rewrite lt0b; clear Fact.
+ apply/hasP; exists j.
+ { rewrite /arrivals_of_task_before /arrivals_of_task_between.
+ rewrite /arrivals_of_task_between mem_filter; apply/andP; split; first by rewrite /is_job_of_task.
+ by unfold jobs_arrived_before in ARR; apply jobs_arrived_between_sub with (t2 := 0) (t3 := upp).
+ }
+ { case HP: (higher_eq_priority s j).
+ { apply/orP; right.
+ rewrite /is_interference_from_another_job_with_higher_eq_priority SCHED.
+ by rewrite /another_job_with_higher_eq_priority NEQ Bool.andb_true_r. }
+ { apply/orP; left.
+ by rewrite /is_priority_inversion /BusyIntervalJLFP.is_priority_inversion SCHED HP.
+ }
+ }
+ }
+ Qed.
+
+ (* In this section we prove that the (abstract) cumulative interfering workload is equivalent to
+ conventional workload, i.e., the one defined with concrete schedule parameters. *)
+ Section InstantiatedWorkloadEquivalence.
+
+ (* Let [t1,t2) be any time interval. *)
+ Variables t1 t2: time.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+
+ (* Then for any job j, the cumulative interfering workload is equal to the conventional workload. *)
+ Lemma instantiated_cumulative_workload_of_hep_jobs_equal_total_workload_of_hep_jobs:
+ cumulative_interfering_workload_of_jobs_with_hep_priority j t1 t2
+ = workload_of_other_jobs_with_hep_priority j t1 t2.
+ Proof.
+ intros.
+ unfold cumulative_interfering_workload_of_jobs_with_hep_priority, workload_of_other_jobs_with_hep_priority.
+ case NEQ: (t1 < t2); last first.
+ { move: NEQ => /negP /negP; rewrite leqNgt; move => NEQ.
+ rewrite big_geq; last by done.
+ rewrite /arrivals_between /jobs_arrived_between big_geq; last by done.
+ by rewrite /workload_of_jobs big_nil.
+ }
+ { unfold interfering_workload_of_jobs_with_hep_priority, workload_of_jobs.
+ have EX: exists k, t2 = t1 + k.
+ { exists (t2  t1). rewrite subnKC. by done. by rewrite ltnW. }
+ move: EX => [k EQ]. subst t2. clear NEQ.
+ induction k.
+  rewrite !addn0.
+ rewrite big_geq; last by done.
+ rewrite /arrivals_between /jobs_arrived_between big_geq; last by done.
+ by rewrite /workload_of_jobs big_nil.
+  rewrite addnS big_nat_recr //=; last by rewrite leq_addr.
+ rewrite IHk.
+ rewrite /arrivals_between /jobs_arrived_between big_nat_recr //=; last by rewrite leq_addr.
+ by rewrite big_cat //=.
+ }
+ Qed.
+
+ End InstantiatedWorkloadEquivalence.
+
+ (* In this section we prove that the (abstract) cumulative interference of jobs with higher or
+ equal priority is equal to total service of jobs with higher or equal priority. *)
+ Section InstantiatedServiceEquivalences.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+
+ (* We consider an arbitrary time interval [t1, t) that starts with a quiet time. *)
+ Variable t1 t: time.
+ Hypothesis H_quiet_time: quiet_time j t1.
+
+ (* Then for any job j, the (abstract) instantiated function of interference is
+ equal to the total service of jobs with higher or equal priority. *)
+ Lemma instantiated_cumulative_interference_of_hep_jobs_equal_total_interference_of_hep_jobs:
+ cumulative_interference_from_other_jobs j t1 t = service_of_other_jobs_with_hep_priority j t1 t.
+ Proof.
+ { rewrite /cumulative_interference_from_other_jobs /is_interference_from_another_job_with_higher_eq_priority
+ /service_of_other_jobs_with_hep_priority.
+ case NEQ: (t1 <= t); last first.
+ { apply negbT in NEQ; rewrite ltnNge in NEQ.
+ rewrite big_geq; last by apply ltnW.
+ rewrite /service_of_jobs /arrivals_between /jobs_arrived_between big_geq; last by apply ltnW.
+ by rewrite big_nil.
+ }
+ have EX: exists k, t = t1 + k.
+ { by exists (t  t1); rewrite subnKC. } move: EX => [k EQ]. subst t. clear NEQ.
+ induction k.
+  rewrite addn0 big_geq; last by done.
+ by rewrite /arrivals_between /jobs_arrived_between big_geq // /service_of_jobs big_nil.
+  unfold service_of_jobs, service_during.
+ unfold is_interference_from_another_job_with_higher_eq_priority.
+ rewrite addnS.
+ rewrite big_nat_recr //=.
+ unfold arrivals_between, jobs_arrived_between.
+ rewrite big_nat_recr //=.
+ rewrite big_cat //=.
+ rewrite IHk.
+ have EQ:
+ \sum_(i0 < jobs_arriving_at arr_seq (t1 + k)  higher_eq_priority i0 j && (i0 != j))
+ \sum_(t1 <= t0 < (t1 + k).+1) service_at sched i0 t0
+ =
+ \sum_(i0 < jobs_arriving_at arr_seq (t1 + k)  higher_eq_priority i0 j && (i0 != j))
+ \sum_(t1 + k <= t0 < (t1 + k).+1) service_at sched i0 t0.
+ {
+ rewrite big_seq_cond [X in _ = X]big_seq_cond.
+ apply/eqP; rewrite eqn_leq; apply/andP; split.
+ {
+ rewrite leq_sum //.
+ move => jo /andP [ARR /andP [HP NTSK]].
+ rewrite (@big_cat_nat _ _ _ (t1 + k)) //=.
+ rewrite [X in _ <= X]add0n leq_add //.
+ rewrite leqn0.
+ rewrite big_nat_cond.
+ rewrite big1 //.
+ move => x /andP [/andP [_ LT] _].
+ apply/eqP; rewrite eqb0; apply/negP; intros NSCHED.
+ unfold jobs_must_arrive_to_execute, arrival_times_are_consistent in *.
+ apply H_jobs_must_arrive_to_execute in NSCHED.
+ unfold has_arrived in NSCHED.
+ apply H_arrival_times_are_consistent in ARR.
+ rewrite ARR in LT.
+ by move: LT; rewrite ltnNge; move => /negP LT.
+ by rewrite leq_addr.
+ }
+ {
+ rewrite leq_sum //.
+ move => jo /andP [ARR /andP [HP NTSK]].
+ rewrite [X in _ <= X](@big_cat_nat _ _ _ (t1 + k )) //=. rewrite leq_addl //.
+ by rewrite leq_addr.
+ }
+ }
+ rewrite EQ.
+ apply/eqP.
+ rewrite exchange_big //=.
+ rewrite (@big_cat_nat _ _ _ (t1 + k)) //=.
+ rewrite exchange_big //=.
+ rewrite big_nat1.
+ rewrite addnA.
+ rewrite eqn_add2l.
+ rewrite exchange_big //=.
+ rewrite big_nat1.
+ rewrite big_cat //=. rewrite big_nat_recr //=.
+ clear EQ IHk.
+ case SCHED: (sched (t1 + k)) => [jo  ].
+ case PRIO: (another_job_with_higher_eq_priority jo j).
+ { simpl.
+ rewrite eqn_leq; apply/andP; split; last by apply service_of_jobs_le_1 with job_arrival.
+ rewrite (big_rem jo) //=.
+ rewrite PRIO /service_at /scheduled_at SCHED eq_refl add1n; by done.
+ apply arrived_between_implies_in_arrivals with (job_arrival0 := job_arrival); try done.
+ unfold jobs_come_from_arrival_sequence in *.
+ apply H_jobs_come_from_arrival_sequence with (t1 + k). by rewrite /scheduled_at SCHED.
+ { move: PRIO => /andP [PRIO1 PRIO2].
+ rewrite /arrived_between ltnS; apply/andP; split.
+ { rewrite leqNgt; apply/negP; intros AB.
+ move: (SCHED) => /eqP /negP SCHED2; apply: SCHED2.
+ apply/negP.
+ apply completed_implies_not_scheduled with job_cost; try done.
+ apply completion_monotonic with t1; try done.
+ rewrite leq_addr; by done.
+ apply H_quiet_time; try done.
+ move: SCHED => /eqP SCHED.
+ by apply H_jobs_come_from_arrival_sequence in SCHED.
+ }
+ {
+ move: SCHED => /eqP SCHED.
+ by apply H_jobs_must_arrive_to_execute in SCHED.
+ }
+ }
+ }
+ {
+ simpl.
+ rewrite eq_sym big1 //.
+ intros joo PRIO2.
+ apply/eqP; rewrite eqb0; apply/negP; intros SCHED2.
+ move: SCHED2 => /eqP SCHED2.
+ rewrite SCHED2 in SCHED.
+ inversion SCHED; subst joo.
+ by rewrite PRIO in PRIO2.
+ }
+ { simpl.
+ rewrite eq_sym big1 //.
+ intros.
+ by rewrite /service_at /scheduled_at SCHED.
+ }
+ by rewrite leq_addr.
+ by rewrite leq_addr .
+ by rewrite leq_addr.
+ by rewrite leq_addr.
+ }
+ Qed.
+
+ (* The same applies to the alternative definition of interference. *)
+ Lemma instantiated_cumulative_interference_of_hep_tasks_equal_total_interference_of_hep_tasks:
+ cumulative_interference_from_other_tasks j t1 t = service_of_jobs_from_other_tasks_with_hep_priority j t1 t.
+ Proof.
+ rewrite /cumulative_interference_from_other_tasks /service_of_jobs_from_other_tasks_with_hep_priority
+ /job_from_another_task_with_higher_eq_priority.
+ case NEQ: (t1 <= t); last first.
+ { apply negbT in NEQ; rewrite ltnNge in NEQ.
+ rewrite big_geq; last by apply ltnW.
+ rewrite /service_of_jobs /arrivals_between /jobs_arrived_between big_geq; last by apply ltnW.
+ by rewrite big_nil.
+ }
+ { have EX: exists k, t = t1 + k; first by exists (t  t1); rewrite subnKC.
+ move: EX => [k EQ]; subst t; clear NEQ.
+ induction k.
+  rewrite addn0 big_geq; last by done.
+ by rewrite /arrivals_between /jobs_arrived_between big_geq // /service_of_jobs big_nil.
+  unfold service_of_jobs, service_during.
+ unfold is_interference_from_another_job_with_higher_eq_priority.
+ rewrite addnS.
+ rewrite big_nat_recr //=.
+ unfold arrivals_between, jobs_arrived_between.
+ rewrite big_nat_recr //=.
+ rewrite big_cat //=.
+ rewrite IHk.
+ have EQ:
+ \sum_(i0 < jobs_arriving_at arr_seq (t1 + k)  higher_eq_priority i0 j &&
+ (job_task i0 != job_task j))
+ \sum_(t1 <= t0 < (t1 + k).+1) service_at sched i0 t0
+ =
+ \sum_(i0 < jobs_arriving_at arr_seq (t1 + k)  higher_eq_priority i0 j &&
+ (job_task i0 != job_task j))
+ \sum_(t1 + k <= t0 < (t1 + k).+1) service_at sched i0 t0.
+ {
+ rewrite big_seq_cond [X in _ = X]big_seq_cond.
+ apply/eqP; rewrite eqn_leq; apply/andP; split.
+ {
+ rewrite leq_sum //.
+ move => jo /andP [ARR /andP [HP NTSK]].
+ rewrite (@big_cat_nat _ _ _ (t1 + k)) //=.
+ rewrite [X in _ <= X]add0n leq_add //.
+ rewrite leqn0.
+ rewrite big_nat_cond.
+ rewrite big1 //.
+ move => x /andP [/andP [_ LT] _].
+ apply/eqP; rewrite eqb0; apply/negP; intros NSCHED.
+ unfold jobs_must_arrive_to_execute, arrival_times_are_consistent in *.
+ apply H_jobs_must_arrive_to_execute in NSCHED.
+ unfold has_arrived in NSCHED.
+ apply H_arrival_times_are_consistent in ARR.
+ rewrite ARR in LT.
+ by move: LT; rewrite ltnNge; move => /negP LT.
+ by rewrite leq_addr.
+ }
+ {
+ rewrite leq_sum //.
+ move => jo /andP [ARR /andP [HP NTSK]].
+ rewrite [X in _ <= X](@big_cat_nat _ _ _ (t1 + k )) //=. rewrite leq_addl //.
+ by rewrite leq_addr.
+ }
+ }
+ rewrite EQ.
+ apply/eqP.
+ rewrite exchange_big //=.
+ rewrite (@big_cat_nat _ _ _ (t1 + k)) //=.
+ rewrite exchange_big //=.
+ rewrite big_nat1.
+ rewrite addnA.
+ rewrite eqn_add2l.
+ rewrite exchange_big //=.
+ rewrite big_nat1.
+ rewrite big_cat //=. rewrite big_nat_recr //=.
+ clear EQ IHk.
+ case SCHED: (sched (t1 + k)) => [jo  ].
+ unfold is_interference_from_another_task_with_higher_eq_priority.
+ case PRIO: (job_from_another_task_with_higher_eq_priority jo j).
+ { simpl.
+ rewrite eqn_leq; apply/andP; split.
+ { rewrite (big_rem jo) //=.
+ unfold job_from_another_task_with_higher_eq_priority in PRIO.
+ rewrite PRIO /job_from_another_task_with_higher_eq_priority
+ /is_interference_from_another_task_with_higher_eq_priority /service_at
+ /scheduled_at SCHED eq_refl add1n PRIO; by done.
+ apply arrived_between_implies_in_arrivals with (job_arrival0 := job_arrival); try done.
+ unfold jobs_come_from_arrival_sequence in *.
+ apply H_jobs_come_from_arrival_sequence with (t1 + k). by rewrite /scheduled_at SCHED.
+ { move: PRIO => /andP [PRIO1 PRIO2].
+ rewrite /arrived_between ltnS; apply/andP; split.
+ { rewrite leqNgt; apply/negP; intros AB.
+ move: (SCHED) => /eqP /negP SCHED2; apply: SCHED2.
+ apply/negP.
+ apply completed_implies_not_scheduled with job_cost; try done.
+ apply completion_monotonic with t1; try done.
+ rewrite leq_addr; by done.
+ apply H_quiet_time; try done.
+ move: SCHED => /eqP SCHED.
+ by apply H_jobs_come_from_arrival_sequence in SCHED.
+ }
+ {
+ move: SCHED => /eqP SCHED.
+ by apply H_jobs_must_arrive_to_execute in SCHED.
+ }
+ }
+ }
+ {
+ rewrite SCHED PRIO.
+ by apply service_of_jobs_le_1 with job_arrival.
+ }
+ }
+ {
+ simpl. rewrite SCHED.
+ rewrite eq_sym big1. rewrite PRIO //.
+ intros joo PRIO2.
+ apply/eqP; rewrite eqb0; apply/negP; intros SCHED2.
+ move: SCHED2 => /eqP SCHED2.
+ rewrite SCHED2 in SCHED.
+ inversion SCHED; subst joo.
+ unfold job_from_another_task_with_higher_eq_priority in PRIO.
+ by rewrite PRIO in PRIO2.
+ }
+ { simpl.
+ rewrite /is_interference_from_another_task_with_higher_eq_priority eq_sym big1 //.
+ rewrite SCHED; by done.
+ intros.
+ by rewrite /service_at /scheduled_at SCHED.
+ }
+ by rewrite leq_addr.
+ by rewrite leq_addr .
+ by rewrite leq_addr.
+ by rewrite leq_addr.
+ }
+ Qed.
+
+ End InstantiatedServiceEquivalences.
+
+ (* In this section we prove that the abstract definition of busy interval is equivalent to
+ the conventional, concrete definition of busy interval for JLFP scheduling. *)
+ Section BusyIntervalEquivalence.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* We prove that the concept of quiet time obtained by instantiating the abstract
+ definition of quiet time coincides with the conventional definition of quiet time
+ (which is defined in module limited.busy_interval). *)
+ Lemma instantiated_quiet_time_equivalent_edf_quiet_time:
+ forall t,
+ quiet_time j t <>
+ AbstractRTADefinitions.quiet_time job_arrival job_cost sched interference interfering_workload j t.
+ Proof.
+ have zero_is_quiet_time: forall j, quiet_time j 0.
+ { by intros jhp ARR HP AB; move: AB; rewrite /arrived_before ltn0. }
+ have CIS := cumulative_interference_split.
+ have IC1 := instantiated_cumulative_interference_of_hep_jobs_equal_total_interference_of_hep_jobs.
+ have IC2 := instantiated_cumulative_interference_of_hep_tasks_equal_total_interference_of_hep_tasks.
+ rewrite /cumulative_interference
+ /cumulative_interference_from_other_jobs
+ /interference /interfering_workload /cumulative_interference_from_other_tasks
+ /service_of_jobs_from_other_tasks_with_hep_priority
+ /service_of_other_jobs_with_hep_priority /job_from_another_task_with_higher_eq_priority
+ in CIS, IC1, IC2.
+ intros t; split; intros.
+ { unfold AbstractRTADefinitions.quiet_time; split.
+ { rewrite /cumulative_interference /AbstractRTADefinitions.cumul_interference
+ /AbstractRTADefinitions.cumul_interfering_workload
+ /cumulative_interference_from_other_jobs
+ /interference /interfering_workload.
+ rewrite CIS !big_split //=.
+ apply/eqP; rewrite eqn_add2l.
+ have L11 := all_jobs_have_completed_equiv_workload_eq_service.
+ rewrite IC1; last by apply zero_is_quiet_time.
+ have L2 := instantiated_cumulative_workload_of_hep_jobs_equal_total_workload_of_hep_jobs;
+ rewrite /cumulative_interfering_workload_of_jobs_with_hep_priority in L2.
+ rewrite L2.
+ rewrite eq_sym; apply/eqP.
+ apply L11 with job_arrival; try done.
+ intros.
+ apply H; try done.
+ apply in_arrivals_implies_arrived in H0; by done.
+ move: H1 => /andP [H3 H4].
+ unfold FP_to_JLFP. by done.
+ apply in_arrivals_implies_arrived_between with (job_arrival0 := job_arrival) in H0; try done.
+ }
+ {
+ unfold pending_earlier_and_at.
+ rewrite negb_and Bool.negb_involutive; apply/orP.
+ case ARR: (arrived_before job_arrival j t); [right  by left].
+ by apply H.
+ }
+ }
+ {
+ intros jhp ARR HP ARB.
+ eapply all_jobs_have_completed_equiv_workload_eq_service with
+ (P := (fun jhp => higher_eq_priority jhp j)) (t1 := 0)(t2 := t); eauto 2; last first.
+ eapply arrived_between_implies_in_arrivals; eauto 2.
+ move: H => [H0 H1].
+ move: H0.
+ rewrite /AbstractRTADefinitions.cumul_interference /AbstractRTADefinitions.cumul_interfering_workload
+ /interference /interfering_workload.
+ rewrite CIS !big_split //=; move => /eqP; rewrite eqn_add2l.
+ rewrite IC1; last by apply zero_is_quiet_time.
+ have L2 := instantiated_cumulative_workload_of_hep_jobs_equal_total_workload_of_hep_jobs;
+ rewrite /cumulative_interfering_workload_of_jobs_with_hep_priority in L2.
+ rewrite L2. move => H2.
+ have H2EQ:
+ service_of_jobs sched (arrivals_between 0 t)
+ (fun jhp : Job =>
+ higher_eq_priority jhp j) 0 t ==
+ workload_of_jobs job_cost (arrivals_between 0 t)
+ (fun jhp : Job =>
+ higher_eq_priority jhp j).
+ { move: H1; rewrite negb_and Bool.negb_involutive leqNgt; move => /orP [H1  H1].
+ { intros.
+ have NOTIN: j \notin arrivals_between 0 t.
+ { apply/memPn.
+ intros jo IN; apply/negP; intros EQ; move: EQ => /eqP EQ.
+ subst jo.
+ unfold arrivals_between in *.
+ apply in_arrivals_implies_arrived_between with (job_arrival0:= job_arrival) in IN; try done.
+ by move: IN => /andP [_ IN]; move: H1; rewrite leqNgt; move => /negP LT; apply: LT.
+ }
+ have UL1 := sum_notin_rem_eqn.
+ rewrite /workload_of_other_jobs_with_hep_priority
+ /another_job_with_higher_eq_priority in H2.
+ by rewrite /service_of_jobs /workload_of_jobs !sum_notin_rem_eqn in H2.
+ }
+ {
+ have JIN: j \in arrivals_between 0 t.
+ { eapply completed_implies_scheduled_before in H1; eauto 2.
+ apply arrived_between_implies_in_arrivals with (job_arrival0:= job_arrival); try done.
+ move: H1 => [t' [H3 _]].
+ apply/andP; split; first by done.
+ move: H3 => /andP [H3e H3t].
+ by apply leq_ltn_trans with t'.
+ }
+ have UNIC: uniq (arrivals_between 0 t).
+ { by eapply arrivals_uniq; eauto 2. }
+ unfold service_of_jobs, workload_of_jobs in H2.
+ unfold service_of_jobs, workload_of_jobs.
+ rewrite big_mkcond //=.
+ rewrite (bigD1_seq j) //=.
+ rewrite big_mkcondl //=.
+ move: H2 => /eqP H2. rewrite H2.
+ rewrite [X in _ == X]big_mkcond //=.
+ rewrite [X in _ == X](bigD1_seq j) //=.
+ rewrite big_mkcondl //=.
+ rewrite eqn_add2r H_priority_is_reflexive.
+ by rewrite eqn_leq; apply/andP; split; try eauto 2.
+ }
+ }
+ by move: H2EQ => /eqP H2EQ.
+ }
+ Qed.
+
+ (* Based on that, we prove that the concept of busy interval obtained by instantiating the abstract
+ definition of busy interval coincides with the conventional definition of busy interval. *)
+ Lemma instantiated_busy_interval_equivalent_edf_busy_interval:
+ forall t1 t2,
+ busy_interval job_arrival job_cost arr_seq sched higher_eq_priority j t1 t2 <>
+ AbstractRTADefinitions.busy_interval job_arrival job_cost sched interference interfering_workload j t1 t2.
+ Proof.
+ split.
+ {
+ move => [[NEQ [QTt1 [NQT REL]] QTt2]].
+  split; last by eapply instantiated_quiet_time_equivalent_edf_quiet_time in QTt2; eauto 2.
+  split; first by done.
+  split; first by apply instantiated_quiet_time_equivalent_edf_quiet_time in QTt1; eauto 2.
+ by intros t NEQ' QT; eapply NQT; eauto 2; apply instantiated_quiet_time_equivalent_edf_quiet_time.
+ }
+ { move => [[/andP [NEQ1 NEQ2] [QTt1 NQT] QTt2]].
+  split; last by eapply instantiated_quiet_time_equivalent_edf_quiet_time; eauto 2.
+  split; first by apply leq_ltn_trans with (job_arrival j).
+  split; first by eapply instantiated_quiet_time_equivalent_edf_quiet_time; eauto 2.
+  split; first by intros t NEQ QT; eapply NQT; eauto 2; eapply instantiated_quiet_time_equivalent_edf_quiet_time in QT; eauto 2.
+  by apply/andP; split.
+ }
+ Qed.
+
+ End BusyIntervalEquivalence.
+
+ End Equivalences.
+
+ End Instantiation.
+
+End JLFPInstantiation.
\ No newline at end of file
diff git a/model/schedule/uni/limited/platform/definitions.v b/model/schedule/uni/limited/platform/definitions.v
new file mode 100644
index 0000000000000000000000000000000000000000..a355e2e4419059fa0d77978839fa634711706bda
 /dev/null
+++ b/model/schedule/uni/limited/platform/definitions.v
@@ 0,0 +1,239 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task
+ rt.model.priority
+ rt.model.arrival.basic.task_arrival.
+Require Import rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.service
+ rt.model.schedule.uni.basic.platform.
+Require Import rt.model.schedule.uni.nonpreemptive.schedule.
+
+From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
+
+(** * Platform with limited preemptions *)
+(** In this module we introduce the notion of whether a job can be preempted at a given time
+ (using a predicate can_be_preempted). In addition, we provide instantiations of the
+ predicate for various preemption models. *)
+Module LimitedPreemptionPlatform.
+
+ Import Epsilon Job SporadicTaskset UniprocessorSchedule Priority Service.
+
+ (* In this section, we define a processor platform with limited preemptions. *)
+ Section Properties.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any uniprocessor schedule of these jobs. *)
+ Variable sched: schedule Job.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_pending := pending job_arrival job_cost sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+
+ (* First, we define the notion of a preemption time. *)
+ Section PreemptionTime.
+
+ (* Let can_be_preempted be a function that maps a job j and the progress of j
+ at some time instant t to a boolean value, i.e., true if job j can be
+ preempted at this point of execution and false otherwise. *)
+ Variable can_be_preempted: Job > time > bool.
+
+ (* We say that a time instant t is a preemption time iff there's no job currently
+ scheduled at t that cannot be preempted (according to the predicate). *)
+ Definition preemption_time (t: time) :=
+ if sched t is Some j then
+ can_be_preempted j (service sched j t)
+ else true.
+
+ (* Since the notion of preemption time is based on an userprovided
+ predicate (variable can_be_preempted), it does not guarantee that
+ the scheduler will enforce correct behavior. For that, we must
+ define additional predicates. *)
+ Section CorrectPreemptionModel.
+
+ (* First, if a job j is not preemptive at some time instant t,
+ then j must be scheduled at time t. *)
+ Definition not_preemptive_implies_scheduled (j: Job) :=
+ forall t,
+ ~~ can_be_preempted j (service sched j t) >
+ job_scheduled_at j t.
+
+ (* A job can start its execution only from a preemption point. *)
+ Definition execution_starts_with_preemption_point (j: Job) :=
+ forall prt,
+ ~~ job_scheduled_at j prt >
+ job_scheduled_at j prt.+1 >
+ can_be_preempted j (service sched j prt.+1).
+
+ (* We say that a model is a correct preemption model if both
+ definitions given above are satisfied for any job. *)
+ Definition correct_preemption_model :=
+ forall j,
+ arrives_in arr_seq j >
+ not_preemptive_implies_scheduled j
+ /\ execution_starts_with_preemption_point j.
+
+ End CorrectPreemptionModel.
+
+ (* Note that for analysis purposes, it is important that the distance
+ between preemption points of a job is bounded. To ensure that, we
+ define next the model of bounded nonpreemptive segment. *)
+ Section ModelWithBoundedNonpreemptiveRegions.
+
+ (* We require that a job has to be executed at least one time instant
+ in order to reach a nonpreemptive segment. *)
+ Definition job_cannot_become_nonpreemptive_before_execution (j: Job) :=
+ can_be_preempted j 0.
+
+ (* And vice versa, a job cannot remain nonpreemptive after its completion. *)
+ Definition job_cannot_be_nonpreemptive_after_completion (j: Job) :=
+ can_be_preempted j (job_cost j).
+
+ (* Consider a function that maps a job to the length of
+ its maximal nonpreemptive segment. *)
+ Variable job_max_nps: Job > time.
+
+ (* And a function task_max_nps... *)
+ Variable task_max_nps: Task > time.
+
+ (* ...that gives an upper bound for values of the function job_max_nps. *)
+ Definition job_max_nonpreemptive_segment_le_task_max_nonpreemptive_segment (j: Job) :=
+ arrives_in arr_seq j >
+ job_max_nps j <= task_max_nps (job_task j).
+
+ (* Next, we say that all the segments of a job j have bounded length iff for any
+ progress progr of job j there exists a preemption point preeemption_point such that
+ [progr <= preemption_point <= progr + (job_max_nps j  ε)]. That is, in any time
+ interval of length [job_max_nps j], there exists a preeemption point which
+ lies in this interval. *)
+ Definition nonpreemptive_regions_have_bounded_length (j: Job) :=
+ forall progr,
+ 0 <= progr <= job_cost j >
+ exists preemption_point,
+ progr <= preemption_point <= progr + (job_max_nps j  ε) /\
+ can_be_preempted j preemption_point.
+
+ (* Finally, we say that the schedule enforces bounded nonpreemptive segments
+ iff the predicate can_be_preempted satisfies the two conditions above. *)
+ Definition model_with_bounded_nonpreemptive_segments :=
+ forall j,
+ arrives_in arr_seq j >
+ job_cannot_become_nonpreemptive_before_execution j
+ /\ job_cannot_be_nonpreemptive_after_completion j
+ /\ job_max_nonpreemptive_segment_le_task_max_nonpreemptive_segment j
+ /\ nonpreemptive_regions_have_bounded_length j.
+
+ End ModelWithBoundedNonpreemptiveRegions.
+
+ (* In this section we prove a few basic properties of the can_be_preempted predicate. *)
+ Section Lemmas.
+
+ Variable job_max_nps: Job > time.
+ Variable task_max_nps: Task > time.
+
+ (* Consider the correct model with bounded nonpreemptive segments. *)
+ Hypothesis H_correct_preemption_model: correct_preemption_model.
+ Hypothesis H_model_with_bounded_np_segments:
+ model_with_bounded_nonpreemptive_segments job_max_nps task_max_nps.
+
+ (* Assume jobs come from some arrival sequence. *)
+ Hypothesis H_jobs_come_from_arrival_sequence:
+ jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* Then, we can show that time 0 is a preemption time. *)
+ Lemma zero_is_pt: preemption_time 0.
+ Proof.
+ unfold preemption_time.
+ case SCHED: (sched 0) => [j  ]; last by done.
+ move: (SCHED) => /eqP ARR.
+ apply H_jobs_come_from_arrival_sequence in ARR.
+ rewrite /service /service_during big_geq; last by done.
+ by move: (H_model_with_bounded_np_segments j ARR) => [PP _]; apply PP.
+ Qed.
+
+ (* Also, we show that the first instant of execution is a preemption time. *)
+ Lemma first_moment_is_pt:
+ forall j prt,
+ arrives_in arr_seq j >
+ ~~ job_scheduled_at j prt >
+ job_scheduled_at j prt.+1 >
+ preemption_time prt.+1.
+ Proof.
+ intros s pt ARR NSCHED SCHED.
+ unfold preemption_time.
+ move: (SCHED) => /eqP SCHED2; rewrite SCHED2; clear SCHED2.
+ by move: (H_correct_preemption_model s ARR) => [_ FHF]; auto.
+ Qed.
+
+ End Lemmas.
+
+ End PreemptionTime.
+
+ (* Next, we define properties related to execution. *)
+ Section Execution.
+
+ (* Similarly to preemptive scheduling, we say that the schedule is
+ workconserving iff whenever a job is backlogged, the processor
+ is always busy scheduling another job. *)
+ (* Imported from the preemptive schedule. *)
+ Definition work_conserving := Platform.work_conserving job_cost.
+
+ End Execution.
+
+ (* Next, we define properties related to FP scheduling. *)
+ Section FP.
+
+ (* Consider any preemption model. *)
+ Variable preemption_model: Job > time > bool.
+
+ (* We say that an FP policy...*)
+ Variable higher_eq_priority: FP_policy Task.
+
+ (* ...is respected by the schedule iff, at every preemption point,
+ a scheduled task has higher (or same) priority than (as)
+ any backlogged task. *)
+ Definition respects_FP_policy_at_preemption_point :=
+ forall j j_hp t,
+ preemption_time preemption_model t >
+ arrives_in arr_seq j >
+ backlogged job_arrival job_cost sched j t >
+ scheduled_at sched j_hp t >
+ higher_eq_priority (job_task j_hp) (job_task j).
+
+ End FP.
+
+ (* Next, we define properties related to JLFP policies. *)
+ Section JLFP.
+
+ (* Consider a scheduling model. *)
+ Variable preemption_model: Job > time > bool.
+
+ (* We say that a JLFP policy ...*)
+ Variable higher_eq_priority: JLFP_policy Job.
+
+ (* ...is respected by the schedule iff, at every preemption point,
+ a scheduled task has higher (or same) priority than (as)
+ any backlogged task. *)
+ Definition respects_JLFP_policy_at_preemption_point :=
+ forall j j_hp t,
+ preemption_time preemption_model t >
+ arrives_in arr_seq j >
+ backlogged job_arrival job_cost sched j t >
+ scheduled_at sched j_hp t >
+ higher_eq_priority j_hp j.
+
+ End JLFP.
+
+ End Properties.
+
+End LimitedPreemptionPlatform.
\ No newline at end of file
diff git a/model/schedule/uni/limited/platform/limited.v b/model/schedule/uni/limited/platform/limited.v
new file mode 100644
index 0000000000000000000000000000000000000000..0e6dd92b7fc3b1ca0e706ec1d24e49f3e55d1515
 /dev/null
+++ b/model/schedule/uni/limited/platform/limited.v
@@ 0,0 +1,413 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job rt.model.arrival.basic.task.
+Require Import rt.model.schedule.uni.schedule.
+Require Export rt.model.schedule.uni.limited.platform.definitions.
+Require Export rt.model.schedule.uni.limited.platform.util.
+
+From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
+
+(** * Platform for models with limited preemptions *)
+(** In module uni.limited.platform we introduce the notion of whether a job can be
+ preempted at a given time (using a predicate can_be_preempted). In this section,
+ we instantiate can_be_preempted for the model with fixed preemption points and
+ model with floating nonpreemptive regions. *)
+Module ModelWithLimitedPreemptions.
+
+ Import Epsilon Job NondecreasingSequence UniprocessorSchedule LimitedPreemptionPlatform.
+
+ (* In this section, we instantiate can_be_preempted for the model with fixed preemption points and
+ the model with floating nonpreemptive regions. We also prove that the definitions are correct. *)
+ Section ModelsWithLimitedPreemptions.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any job arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* Next, consider a function that maps a job to the sequence of its preemption points. *)
+ Variable job_preemption_points: Job > seq time.
+
+ (* In this section, we provide a set of hypotheses for the models with limited preemptions. *)
+ Section Definitions.
+
+ (* In this section, we introduce the joblevel definitions.
+ They are the same for both models. *)
+ Section ModelWithLimitedPreemptions.
+
+ (* First, we define a function that maps a job to the
+ sequence of lengths of its nonpreemptive segments. *)
+ Definition lengths_of_segments j := distances (job_preemption_points j).
+
+ (* Next, we define a function that maps a job to the
+ length of the longest nonpreemptive segment of job j. *)
+ Definition job_max_nps (j: Job) := max (lengths_of_segments j).
+
+ (* Similarly, job_last is a function that maps a job to the
+ length of the last nonpreemptive segment. *)
+ Definition job_last_nps (j: Job) := last (lengths_of_segments j).
+
+ (* Next, we describe some structural properties that
+ a sequence of preemption points should satisfy. *)
+
+ (* (1) The sequence of preemption points of a job with zero cost is equal to [0; 0]. *)
+ Definition job_with_zero_cost_consists_of_one_empty_segment :=
+ forall j, arrives_in arr_seq j > job_cost j = 0 > job_preemption_points j = [::0; 0].
+
+ (* (2) The last nonpreemptive segment of a job with positive cost cannot be empty. *)
+ Definition last_segment_is_positive :=
+ forall j, arrives_in arr_seq j > job_cost j > 0 > job_last_nps j > 0.
+
+ (* (3) We also require the sequence of preemption points to contain the beginning... *)
+ Definition beginning_of_execution_in_preemption_points :=
+ forall j, arrives_in arr_seq j > first (job_preemption_points j) = 0.
+
+ (* ... and (4) the end of execution for any job j.*)
+ Definition end_of_execution_in_preemption_points :=
+ forall j, arrives_in arr_seq j > last (job_preemption_points j) = job_cost j.
+
+ (* (5) We require the sequence of preemption points to be a nondecreasing sequence. *)
+ Definition preemption_points_is_nondecreasing_sequence :=
+ forall (j: Job),
+ arrives_in arr_seq j >
+ nondecreasing_sequence (job_preemption_points j).
+
+ (* Finally, we define a joblevel model with limited preemptions
+ as a concatenation of the hypotheses above. *)
+ Definition limited_preemptions_job_model :=
+ job_with_zero_cost_consists_of_one_empty_segment /\
+ last_segment_is_positive /\
+ beginning_of_execution_in_preemption_points /\
+ end_of_execution_in_preemption_points /\
+ preemption_points_is_nondecreasing_sequence.
+
+ End ModelWithLimitedPreemptions.
+
+ (* In this section, we define the model with fixed preemption points. *)
+ Section ModelWithFixedPreemptionPoints.
+
+ (* Consider a function that maps a task to the sequence of its preemption points. *)
+ Variable task_preemption_points: Task > seq time.
+
+ (* Similarly to job's nonpreemptive segments, we define the length of the max
+ nonpreemptive segment and lenght of the last nonpreemptive segment. *)
+ Definition task_last_nps tsk := last (distances (task_preemption_points tsk)).
+ Definition task_max_nps tsk := max (distances (task_preemption_points tsk)).
+
+ (* Consider an arbitrary task set ts. *)
+ Variable ts: list Task.
+
+ (* Next, we describe some structural properties that
+ a sequence of preemption points of task should satisfy. *)
+
+ (* (1) We require the sequence of preemption points to contain the beginning... *)
+ Definition task_beginning_of_execution_in_preemption_points :=
+ forall tsk, tsk \in ts > first (task_preemption_points tsk) = 0.
+
+ (* ... and (2) the end of execution for any job j.*)
+ Definition task_end_of_execution_in_preemption_points :=
+ forall tsk, tsk \in ts > last (task_preemption_points tsk) = task_cost tsk.
+
+ (* (3) We require the sequence of preemption points
+ to be a nondecreasing sequence. *)
+ Definition task_preemption_points_is_nondecreasing_sequence :=
+ forall tsk, tsk \in ts > nondecreasing_sequence (task_preemption_points tsk).
+
+ (* (4) Next, we require the number of nonpreemptive segments of a job to be
+ equal to the number of nonpreemptive segments of its task. Note that
+ some of nonpreemptive segments of a job can have zero length, nonetheless
+ the number of segments should match. *)
+ Definition job_consists_of_the_same_number_of_segments_as_task :=
+ forall j,
+ arrives_in arr_seq j >
+ size (job_preemption_points j) = size (task_preemption_points (job_task j)).
+
+ (* (5) We require lengths of nonpreemptive segments of a job to be bounded
+ by lenghts of the corresponding segments of its task. *)
+ Definition lengths_of_task_segments_bound_length_of_job_segments :=
+ forall j n,
+ arrives_in arr_seq j >
+ nth 0 (distances (job_preemption_points j)) n
+ <= nth 0 (distances (task_preemption_points (job_task j))) n.
+
+ (* (6) Lastly, we ban empty nonpreemptive segments for tasks. *)
+ Definition task_segments_are_nonempty :=
+ forall tsk n,
+ (tsk \in ts) >
+ n < size (distances (task_preemption_points tsk)) >
+ ε <= nth 0 (distances (task_preemption_points tsk)) n.
+
+ (* We define a tasklevel model with fixed preemption points
+ as a concatenation of the hypotheses above. *)
+ Definition fixed_preemption_points_task_model :=
+ task_beginning_of_execution_in_preemption_points /\
+ task_end_of_execution_in_preemption_points /\
+ task_preemption_points_is_nondecreasing_sequence /\
+ job_consists_of_the_same_number_of_segments_as_task /\
+ lengths_of_task_segments_bound_length_of_job_segments /\
+ task_segments_are_nonempty.
+
+ (* We define the model with fixed preemption points as
+ the model with fixed preemptions points at the tasklevel
+ and model with limited preemptions at the joblevel. *)
+ Definition fixed_preemption_points_model :=
+ limited_preemptions_job_model /\
+ fixed_preemption_points_task_model.
+
+ End ModelWithFixedPreemptionPoints.
+
+ (* In this section, we define the model with floating nonpreemptive regions. *)
+ Section ModelWithFloatingNonpreemptiveRegions.
+
+ (* Consider a function task_max_nps that maps a task to
+ the lenght of its max nonpreemptive segment. *)
+ Variable task_max_nps: Task > time.
+
+ (* We require [task_max_nps (job_task j)] to be an upper bound
+ of the lenght of the max nonpreemptive segment of job j. *)
+ Definition job_max_np_segment_le_task_max_np_segment :=
+ forall (j: Job),
+ arrives_in arr_seq j >
+ job_max_nps j <= task_max_nps (job_task j).
+
+ (* We define the model with floating nonpreemptive regions as
+ the model with floating nonpreemptive regions at the tasklevel
+ and model with limited preemptions at the joblevel. *)
+ Definition model_with_floating_nonpreemptive_regions :=
+ limited_preemptions_job_model /\
+ job_max_np_segment_le_task_max_np_segment.
+
+ End ModelWithFloatingNonpreemptiveRegions.
+
+ (* Given a list of preemption points for each job, we define the function
+ can_be_preempted for the model with limited preemptions as follows. We say
+ that job j can be preempted at time t iff the service received by j at
+ time t belongs to the list of preemptions points. *)
+ Definition can_be_preempted_for_model_with_limited_preemptions (j: Job) (progr: time) :=
+ progr \in job_preemption_points j.
+
+ (* Based on the definition of the model with limited preemptions,
+ we define a schedule with limited preemptions. *)
+ Definition is_schedule_with_limited_preemptions (sched: schedule Job) :=
+ forall j t,
+ arrives_in arr_seq j >
+ ~~ can_be_preempted_for_model_with_limited_preemptions j (service sched j t) >
+ scheduled_at sched j t.
+
+ End Definitions.
+
+ (* In this section, we prove correctness of the model defined by
+ function model_with_limited_preemptions. *)
+ Section Lemmas.
+
+ (* Consider any uniprocessor schedule with limited preemptions...*)
+ Variable sched: schedule Job.
+ Hypothesis H_is_schedule_with_limited_preemptions:
+ is_schedule_with_limited_preemptions sched.
+
+ (* ...where jobs do not execute after their completion. *)
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Next, we assume that preemption points are defined by the model with
+ floating nonpreemptive regions. Note that the assumptions of the
+ model with floating nonpreemptive regions are a strict subset of
+ the assumptions of the model with fixed preemption points. This
+ guaranties that the results below work for both models. *)
+ Variable task_max_nps: Task > time.
+ Hypothesis H_limited_preemptions_job_model: limited_preemptions_job_model.
+ Hypothesis H_job_max_np_segment_le_task_max_np_segment:
+ job_max_np_segment_le_task_max_np_segment task_max_nps.
+
+ (* First, we prove a few basic auxiliary lemmas. *)
+ Section AuxiliaryLemmas.
+
+ (* Consider a job j. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+
+ (* We prove that the list of preemption points is not empty. *)
+ Lemma list_of_preemption_point_is_not_empty:
+ 0 < size (job_preemption_points j).
+ Proof.
+ move: H_limited_preemptions_job_model => [EMPT [LS [BEG [END _]]]].
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { by specialize (EMPT j H_j_arrives ZERO); rewrite EMPT. }
+ apply/negPn/negP; rewrite eqn0Ngt; intros CONTR; move: CONTR => /eqP CONTR.
+ move: (END _ H_j_arrives) => EQ.
+ move: EQ; rewrite /last nth_last nth_default; last by rewrite CONTR.
+ intros.
+ by rewrite /job_cost_positive EQ in POS.
+ Qed.
+
+ (* We prove that 0 is a preemption point. *)
+ Lemma zero_in_preemption_points: 0 \in job_preemption_points j.
+ Proof.
+ move: H_limited_preemptions_job_model => [EMPT [LS [BEG [END _]]]].
+ move: (BEG _ H_j_arrives) => EQ.
+ rewrite EQ; clear EQ.
+ rewrite /first nth0.
+ apply/(nthP 0).
+ exists 0.
+  by apply list_of_preemption_point_is_not_empty.
+  by done.
+ Qed.
+
+ (* Next, we prove that the cost of a job is a preemption point. *)
+ Lemma job_cost_in_nonpreemptive_points: job_cost j \in job_preemption_points j.
+ Proof.
+ move: H_limited_preemptions_job_model => [EMPT [LS [BEG [END _]]]].
+ move: (END _ H_j_arrives) => EQ.
+ rewrite EQ; clear EQ.
+ rewrite /last nth_last.
+ apply/(nthP 0).
+ exists ((size (job_preemption_points j)).1); last by done.
+ rewrite (leq_add2r 1) !addn1 prednK //.
+ by apply list_of_preemption_point_is_not_empty.
+ Qed.
+
+ (* As a corollary, we prove that the size of the sequence of nonpreemptive points is at least 2. *)
+ Corollary number_of_preemption_points_at_least_two: 2 <= size (job_preemption_points j).
+ Proof.
+ move: H_limited_preemptions_job_model => [EMPT [LS [BEG [END _]]]].
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { by specialize (EMPT j H_j_arrives ZERO); rewrite EMPT. }
+ have EQ: 2 = size [::0; job_cost j]; first by done.
+ rewrite EQ; clear EQ.
+ apply subseq_leq_size.
+ rewrite !cons_uniq.
+ { apply/andP; split.
+ rewrite in_cons negb_or; apply/andP; split; last by done.
+ rewrite neq_ltn; apply/orP; left; eauto 2.
+ apply/andP; split; by done. }
+ intros t EQ; move: EQ; rewrite !in_cons.
+ move => /orP [/eqP EQ /orP [/eqP EQEQ]]; last by done.
+  by rewrite EQ; apply zero_in_preemption_points.
+  by rewrite EQ; apply job_cost_in_nonpreemptive_points.
+ Qed.
+
+ End AuxiliaryLemmas.
+
+ (* We prove that the fixed_preemption_point_model function defines
+ a correct preemption model. *)
+ Lemma model_with_fixed_preemption_points_is_correct:
+ correct_preemption_model arr_seq sched can_be_preempted_for_model_with_limited_preemptions.
+ Proof.
+ intros j ARR; split.
+ { move => t NPP.
+ by apply H_is_schedule_with_limited_preemptions. }
+ { intros t NSCHED SCHED.
+ have SERV: service sched j t = service sched j t.+1.
+ { rewrite [service sched j t]addn0 /service /service_during; apply/eqP.
+ rewrite big_nat_recr //=.
+ rewrite eqn_add2l eq_sym.
+ by rewrite /service_at eqb0. }
+ rewrite [can_be_preempted_for_model_with_limited_preemptions _ _]Bool.negb_involutive.
+ apply/negP; intros CONTR.
+ move: NSCHED => /negP NSCHED; apply: NSCHED.
+ apply H_is_schedule_with_limited_preemptions; first by done.
+ by rewrite SERV.
+ }
+ Qed.
+
+ (* Next we prove that the fixed_preemption_point_model function defines
+ a model with bounded nonpremtive regions. *)
+ Lemma model_with_fixed_preemption_points_is_model_with_bounded_nonpreemptive_regions:
+ model_with_bounded_nonpreemptive_segments
+ job_cost job_task arr_seq can_be_preempted_for_model_with_limited_preemptions
+ job_max_nps task_max_nps.
+ Proof.
+ intros j ARR.
+ move: H_limited_preemptions_job_model => [EMPT [LS [BEG [END NDEC]]]].
+ move: (posnP (job_cost j)) => [ZEROPOS].
+ { specialize (EMPT j ARR ZERO).
+ split; last split; last split.
+  by rewrite /job_cannot_become_nonpreemptive_before_execution /can_be_preempted_for_model_with_limited_preemptions EMPT.
+  by rewrite /job_cannot_be_nonpreemptive_after_completion /can_be_preempted_for_model_with_limited_preemptions EMPT ZERO.
+  by intros _; rewrite /job_max_nps /lengths_of_segments EMPT /distances; simpl; rewrite subn0.
+  move => progr; rewrite ZERO leqn0; move => /andP [_ /eqP LE].
+ exists 0; rewrite LE; split.
+ + by apply/andP; split.
+ + by rewrite /can_be_preempted_for_model_with_limited_preemptions EMPT.
+ }
+ split; last split; last split.
+ { by rewrite /job_cannot_become_nonpreemptive_before_execution; eauto; apply zero_in_preemption_points. }
+ { by apply job_cost_in_nonpreemptive_points. }
+ { by intros ARR2; apply H_job_max_np_segment_le_task_max_np_segment. }
+ { unfold nonpreemptive_regions_have_bounded_length, can_be_preempted_for_model_with_limited_preemptions.
+ move => progr /andP [_ LE].
+ specialize (NDEC j).
+ specialize (H_is_schedule_with_limited_preemptions j).
+ destruct (progr \in job_preemption_points j) eqn:NotIN.
+ { exists progr; split; first apply/andP; first split; try done.
+ by rewrite leq_addr.
+ }
+ set (preemptions := job_preemption_points j).
+ set (serv := progr).
+ have Fact1: job_cost j <= last preemptions.
+ { by apply last_is_max_in_nondecreasing_seq; eauto 2; apply job_cost_in_nonpreemptive_points. }
+ have Fact2: first preemptions <= serv < last preemptions.
+ { apply/andP; split.
+  by rewrite /preemptions BEG.
+  rewrite /serv /preemptions END; last by done.
+ rewrite ltn_neqAle; apply/andP; split; last by done.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ rewrite CONTR in NotIN.
+ move: NotIN => /eqP; rewrite eqbF_neg; move => /negP NIN; apply: NIN.
+ by apply job_cost_in_nonpreemptive_points.
+ }
+ have EX: exists n,
+ n.+1 < size preemptions /\
+ nth 0 preemptions n < serv < nth 0 preemptions n.+1.
+ { intros.
+ move: (belonging_to_segment_of_seq_is_total
+ preemptions serv (number_of_preemption_points_at_least_two _ ARR) Fact2) => [n [SIZE2 /andP [N1 N2]]].
+ exists n; split; first by done.
+ apply/andP; split; last by done.
+ move: N1; rewrite leq_eqVlt; move => /orP [/eqP EQ  G]; last by done.
+ exfalso.
+ move: NotIN => /negP CONTR; apply: CONTR.
+ unfold serv, fixed_preemption_points_model in *.
+ rewrite EQ; clear EQ.
+ rewrite mem_nth //.
+ by apply ltnW.
+ }
+ move: EX => [x [SIZE2 /andP [N1 N2]]].
+ set ptl := nth 0 preemptions x.
+ set ptr := nth 0 preemptions x.+1.
+ exists ptr.
+ split.
+ { apply/andP; split.
+ { by apply ltnW. }
+ {
+ apply leq_trans with (ptl + (job_max_nps j  ε) + 1).
+ { unfold job_max_nps.
+ rewrite addnA leq_subLR.
+ rewrite (leq_add2r 1).
+ rewrite [in X in _ <= X]addnC leq_subLR.
+ rewrite !subn1 !addn1 prednK.
+ { by rewrite [_.+1.1]pred_Sn; apply distance_between_neighboring_elements_le_max_distance_in_seq. }
+ { apply max_distance_in_nontrivial_seq_is_positive; first by eauto 2.
+ exists 0, (job_cost j); repeat split.
+  by apply zero_in_preemption_points.
+  by apply job_cost_in_nonpreemptive_points.
+  apply/eqP; rewrite eq_sym lt0n.
+ by apply POS.
+ }
+ }
+ { rewrite addn1. rewrite ltn_add2r. apply N1. }
+ }
+ }
+ { by apply mem_nth. }
+ }
+ Qed.
+
+ End Lemmas.
+
+ End ModelsWithLimitedPreemptions.
+
+End ModelWithLimitedPreemptions.
\ No newline at end of file
diff git a/model/schedule/uni/limited/platform/nonpreemptive.v b/model/schedule/uni/limited/platform/nonpreemptive.v
new file mode 100644
index 0000000000000000000000000000000000000000..6296c0a8da595c4d8dcf5aa6d9d48a7c638d542f
 /dev/null
+++ b/model/schedule/uni/limited/platform/nonpreemptive.v
@@ 0,0 +1,157 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task
+ rt.model.priority
+ rt.model.arrival.basic.task_arrival.
+Require Import rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.service
+ rt.model.schedule.uni.basic.platform.
+Require Import rt.model.schedule.uni.nonpreemptive.schedule.
+Require Export rt.model.schedule.uni.limited.platform.definitions.
+
+From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
+
+(** * Platform for fully nonpreemptive model *)
+(** In module uni.limited.platform we introduce the notion of whether a job can be preempted
+ at a given time (using a predicate can_be_preempted). In this section, we instantiate
+ can_be_preempted for the fully nonpreemptive model and prove its correctness. *)
+Module FullyNonPreemptivePlatform.
+
+ Import Epsilon Job SporadicTaskset UniprocessorSchedule Priority
+ Service LimitedPreemptionPlatform.
+
+ Section FullyNonPreemptiveModel.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor nonpreemptive schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+ Hypothesis H_nonpreemptive_sched:
+ NonpreemptiveSchedule.is_nonpreemptive_schedule job_cost sched.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_pending := pending job_arrival job_cost sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+
+ (* Assume that a job cost cannot be larger than a task cost. *)
+ Hypothesis H_job_cost_le_task_cost:
+ cost_of_jobs_from_arrival_sequence_le_task_cost
+ task_cost job_cost job_task arr_seq.
+
+ (* We say that the model is fully nonpreemptive
+ iff every job cannot be preempted until its completion. *)
+ Definition can_be_preempted_for_fully_nonpreemptive_model (j: Job) (progr: time) :=
+ (progr == 0)  (progr == job_cost j).
+
+ (* Since in a fully nonpreemptive model a job cannot be preempted after
+ it starts the execution, job_max_nps is equal to job_cost. *)
+ Let job_max_nps (j: Job) := job_cost j.
+
+ (* In order to bound job_max_nps, task_max_nps should be equal to task_cost. *)
+ Let task_max_nps (tsk: Task) := task_cost tsk.
+
+ (* Then, we prove that fully_nonpreemptive_model is a correct preemption model... *)
+ Lemma fully_nonpreemptive_model_is_correct:
+ correct_preemption_model arr_seq sched can_be_preempted_for_fully_nonpreemptive_model.
+ Proof.
+ intros j; split.
+ { move => t.
+ rewrite /can_be_preempted_for_fully_nonpreemptive_model Bool.negb_orb lt0n.
+ move => /andP [POS NCOMPL].
+ unfold NonpreemptiveSchedule.is_nonpreemptive_schedule in *.
+ move: (incremental_service_during _ _ _ _ _ POS) => [ft [/andP [_ LT] [SCHED SERV]]].
+ apply H_nonpreemptive_sched with ft.
+ { by apply ltnW. }
+ { by done. }
+ { rewrite /completed_by ltnNge.
+ move: NCOMPL; rewrite neq_ltn; move => /orP [LEGE]; [by done  exfalso].
+ move: GE; rewrite ltnNge; move => /negP GE; apply: GE.
+ by eauto 2.
+ }
+ }
+ { intros t NSCHED SCHED.
+ rewrite /can_be_preempted_for_fully_nonpreemptive_model.
+ apply/orP; left.
+ apply/negP; intros CONTR.
+ move: CONTR => /negP; rewrite lt0n; intros POS.
+ move: (incremental_service_during _ _ _ _ _ POS) => [ft [/andP [_ LT] [SCHEDn SERV]]].
+ move: NSCHED => /negP NSCHED; apply: NSCHED.
+ apply H_nonpreemptive_sched with ft.
+ { by rewrite ltnS. }
+ { by done. }
+ { rewrite /completed_by ltnNge.
+ apply leq_ltn_trans with (service sched j t.+1).
+ { by rewrite /service /service_during big_nat_recr //= leq_addr. }
+ { rewrite addn1.
+ apply leq_trans with (service sched j t.+2).
+  unfold service, service_during.
+ have EQ: (service_at sched j t.+1) = 1.
+ { by apply/eqP; rewrite eqb1. }
+ by rewrite EQ big_nat_recr //=.
+  by eauto 2.
+ }
+ }
+ }
+ Qed.
+
+ (* ... and has bounded nonpreemptive regions. *)
+ Lemma fully_nonpreemptive_model_is_model_with_bounded_nonpreemptive_regions:
+ model_with_bounded_nonpreemptive_segments
+ job_cost job_task arr_seq can_be_preempted_for_fully_nonpreemptive_model job_max_nps task_max_nps.
+ Proof.
+ have F: forall n, n = 0 \/ n > 0.
+ { by intros n; destruct n; [left  right]. }
+ intros j; split; last split; last split.
+ { by done. }
+ { by apply/orP; right. }
+ { intros ARR.
+ rewrite /job_max_nps /task_max_nps.
+ by eauto 2.
+ }
+ { intros progr.
+ move: (F (progr)) => [EQ  GT].
+ { exists progr; split.
+  by apply/andP; split; [done  rewrite leq_addr].
+  by rewrite /can_be_preempted_for_fully_nonpreemptive_model EQ. }
+ { exists (maxn progr (job_cost j)).
+ have POS: 0 < job_cost j.
+ { by apply leq_trans with progr; last move: H0 => /andP [_ H0]. }
+ split.
+ { apply/andP; split; first by rewrite leq_maxl.
+ rewrite /job_max_nps addnBA; last eauto 2.
+ rewrite geq_max; apply/andP; split.
+  rewrite addnBA; last by eauto 2.
+ by rewrite leq_addr.
+  by rewrite addnC addnBA // leq_addr.
+ }
+ { unfold can_be_preempted_for_fully_nonpreemptive_model.
+ apply/orP; right.
+ move: H0 => /andP [_ LE].
+ rewrite eqn_leq; apply/andP; split.
+  by rewrite geq_max; apply/andP; split.
+  by rewrite leq_max; apply/orP; right.
+ }
+ }
+ }
+ Qed.
+
+ End FullyNonPreemptiveModel.
+
+End FullyNonPreemptivePlatform.
\ No newline at end of file
diff git a/model/schedule/uni/limited/platform/preemptive.v b/model/schedule/uni/limited/platform/preemptive.v
new file mode 100644
index 0000000000000000000000000000000000000000..5f3d24aad671df86b974e4a4b02b36dd5fad4dec
 /dev/null
+++ b/model/schedule/uni/limited/platform/preemptive.v
@@ 0,0 +1,70 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task
+ rt.model.priority
+ rt.model.arrival.basic.task_arrival.
+Require Import rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.service
+ rt.model.schedule.uni.basic.platform.
+Require Export rt.model.schedule.uni.limited.platform.definitions.
+
+From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
+
+(** * Platform for fully premptive model *)
+(** In module uni.limited.platform we introduce the notion of whether a job can be preempted
+ at a given time (using a predicate can_be_preempted). In this section, we instantiate
+ can_be_preempted for the fully preemptive model and prove its correctness. *)
+Module FullyPreemptivePlatform.
+
+ Import Epsilon Job SporadicTaskset UniprocessorSchedule Priority
+ Service LimitedPreemptionPlatform.
+
+ Section FullyPreemptiveModel.
+
+ Context {Task: eqType}.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any job arrival sequence ...*)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any uniprocessor schedule of these jobs. *)
+ Variable sched: schedule Job.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_pending := pending job_arrival job_cost sched.
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+
+ (* In the fully preemptive model any job can be preempted at any time. *)
+ Definition can_be_preempted_for_fully_preemptive_model (j: Job) (progr: time) := true.
+
+ (* Since in a fully preemptive model a job can be preempted at
+ any time job_max_nps cannot be greater than ε. *)
+ Let job_max_nps (j: Job) := ε.
+
+ (* In order to bound job_max_nps, we can choose task_max_nps that is equal to ε for any task. *)
+ Let task_max_nps (tsk: Task) := ε.
+
+ (* Then, we prove that fully_preemptive_model is a correct preemption model... *)
+ Lemma fully_preemptive_model_is_correct:
+ correct_preemption_model arr_seq sched can_be_preempted_for_fully_preemptive_model.
+ Proof. by intros j; split; intros t CONTR. Qed.
+
+ (* ... and has bounded nonpreemptive regions. *)
+ Lemma fully_preemptive_model_is_model_with_bounded_nonpreemptive_regions:
+ model_with_bounded_nonpreemptive_segments
+ job_cost job_task arr_seq can_be_preempted_for_fully_preemptive_model job_max_nps task_max_nps.
+ Proof.
+ intros j; repeat split; try done.
+ intros t; exists t; split.
+ { by apply/andP; split; [ done  rewrite subnn addn0]. }
+ { by done. }
+ Qed.
+
+ End FullyPreemptiveModel.
+
+End FullyPreemptivePlatform.
\ No newline at end of file
diff git a/model/schedule/uni/limited/platform/priority_inversion_is_bounded.v b/model/schedule/uni/limited/platform/priority_inversion_is_bounded.v
new file mode 100644
index 0000000000000000000000000000000000000000..4f84902b3fddbdccdde981d0929440e91e87af9b
 /dev/null
+++ b/model/schedule/uni/limited/platform/priority_inversion_is_bounded.v
@@ 0,0 +1,588 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.schedule.
+Require Import rt.model.schedule.uni.limited.platform.definitions
+ rt.model.schedule.uni.limited.busy_interval.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+(** * Priority inversion is bounded *)
+(** In this module we prove that any priority inversion that occurs in the model with bounded
+ nonpreemptive segments defined in module rt.model.schedule.uni.limited.platform.definitions
+ is bounded. *)
+Module PriorityInversionIsBounded.
+
+ Import Epsilon Job Priority UniprocessorSchedule LimitedPreemptionPlatform BusyIntervalJLFP.
+
+ Section PriorityInversionIsBounded.
+
+ Context {Task: eqType}.
+ Variable task_max_nps task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_max_nps job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+ Hypothesis H_jobs_come_from_arrival_sequence: jobs_come_from_arrival_sequence sched arr_seq.
+
+ (* ... where jobs do not execute before their arrival nor after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* Consider a JLFP policy that indicates a higherorequal priority relation,
+ and assume that the relation is reflexive and transitive. *)
+ Variable higher_eq_priority: JLFP_policy Job.
+ Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.
+
+ (* We consider an arbitrary function can_be_preempted which defines
+ a preemption model with bounded nonpreemptive segments. *)
+ Variable can_be_preempted: Job > time > bool.
+ Let preemption_time := preemption_time sched can_be_preempted.
+ Hypothesis H_correct_preemption_model:
+ correct_preemption_model arr_seq sched can_be_preempted.
+ Hypothesis H_model_with_bounded_nonpreemptive_segments:
+ model_with_bounded_nonpreemptive_segments
+ job_cost job_task arr_seq can_be_preempted job_max_nps task_max_nps.
+
+ (* Next, we assume that the schedule is a workconserving schedule... *)
+ Hypothesis H_work_conserving: work_conserving job_arrival job_cost arr_seq sched.
+
+ (* ... and the schedule respects the policy defined by the
+ can_be_preempted function (i.e., bounded nonpreemptive segments). *)
+ Hypothesis H_respects_policy:
+ respects_JLFP_policy_at_preemption_point
+ job_arrival job_cost arr_seq sched can_be_preempted higher_eq_priority.
+
+ (* Let's define some local names for clarity. *)
+ Let job_scheduled_at := scheduled_at sched.
+ Let job_completed_by := completed_by job_cost sched.
+
+ (* Finally, we introduce the notion of the maximal length of (potential) priority
+ inversion at a time instant t, which is defined as the maximum length of
+ nonpreemptive segments among all jobs that arrived so far. Note that
+ the value [job_max_nps j_lp] is at least ε for any job j_lp, so the maximal
+ length of priority inversion cannot be negative. *)
+ Definition max_length_of_priority_inversion (j: Job) (t: time) :=
+ \max_(j_lp < jobs_arrived_before arr_seq t  ~~ higher_eq_priority j_lp j)
+ (job_max_nps j_lp  ε).
+
+ (** Next we prove that a priority inversion of a job is bounded by
+ function max_length_of_priority_inversion. *)
+
+ (** Note that any bound on function max_length_of_priority_inversion will also be
+ a bound on the maximal priority inversion. This bound may be different
+ for different scheduler and/or task models. Thus, we don't define such a bound
+ in this module. *)
+
+ (* Consider any job j of tsk with positive job cost. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_cost_positive: job_cost_positive job_cost j.
+
+ (* Consider any busy interval prefix [t1, t2) of job j. *)
+ Variable t1 t2: time.
+ Hypothesis H_busy_interval_prefix:
+ busy_interval_prefix job_arrival job_cost arr_seq sched higher_eq_priority j t1 t2.
+
+ (* In this section, we prove that at any time instant after any preemption point
+ (inside the busy interval), the processor is always busy scheduling a
+ job with higher or equal priority. *)
+ Section PreemptionTimeAndPriorityInversion.
+
+ (* First, we show that the processor at any preemptive point is always
+ busy scheduling a job with higher or equal priority. *)
+ Lemma not_quiet_implies_exists_scheduled_hp_job_at_preemption_point:
+ forall t,
+ t1 <= t < t2 >
+ preemption_time t >
+ exists j_hp,
+ arrived_between job_arrival j_hp t1 t2 /\
+ higher_eq_priority j_hp j /\
+ job_scheduled_at j_hp t.
+ Proof.
+ move: (H_busy_interval_prefix) => [SL [QUIET [NOTQUIET INBI]]].
+ rename H_work_conserving into WORK, H_respects_policy into PRIO,
+ H_jobs_come_from_arrival_sequence into CONS.
+ move => t /andP [GEt LEt] PREEMPTP.
+ have NOTIDLE := not_quiet_implies_not_idle
+ job_arrival job_cost arr_seq _
+ sched higher_eq_priority j _ _ _ _ _ t1 t2 _ t.
+ feed_n 8 NOTIDLE; eauto 2.
+ unfold is_idle, FP_is_transitive, transitive in *.
+ destruct (sched t) as [j_hp] eqn:SCHED; [clear NOTIDLE  by exfalso; apply NOTIDLE].
+ move: SCHED => /eqP SCHED.
+ exists j_hp.
+ have HP: higher_eq_priority j_hp j.
+ { apply contraT; move => /negP NOTHP; exfalso.
+ have TEMP: t <= t2.1; first by rewrite subn1 subh3 // addn1.
+ rewrite leq_eqVlt in TEMP; move: TEMP => /orP [/eqP EQUALt2m1  LTt2m1];
+ first rewrite leq_eqVlt in GEt; first move: GEt => /orP [/eqP EQUALt1  LARGERt1].
+ { subst t; clear LEt.
+ rewrite EQUALt1 in SCHED; move: EQUALt1 => /eqP EQUALt1.
+ destruct (job_scheduled_at j t1) eqn:SCHEDj.
+ { simpl. have EQ:= only_one_job_scheduled sched j j_hp t1 SCHEDj SCHED.
+ by subst j; apply NOTHP.
+ }
+ { apply NOTHP.
+ apply PRIO with t1; try done.
+  by move: EQUALt1 => /eqP EQUALt1; rewrite EQUALt1.
+  apply/andP; split; last first.
+ + by move: SCHEDj; rewrite /job_scheduled_at; move => /negP /negP SCHEDj.
+ + have EQ: t1 = job_arrival j.
+ { rewrite eqSS in EQUALt1.
+ have EQ: t2 = t1.+1.
+ { rewrite prednK in EQUALt1; first by apply/eqP; rewrite eq_sym.
+ apply negbNE; rewrite eqn0Ngt; apply/neqP; intros EQ0.
+ move: INBI; rewrite EQ0; move => /andP [_ CONTR].
+ by rewrite ltn0 in CONTR.
+ } clear EQUALt1.
+ by move: INBI; rewrite EQ ltnS eqn_leq; move => /eqP INBI.
+ }
+ by rewrite EQ; eapply job_pending_at_arrival; eauto 2.
+ }
+ }
+ { feed (NOTQUIET t); first by apply/andP; split.
+ apply NOTQUIET; intros j_hp' IN HP ARR.
+ apply contraT; move => /negP NOTCOMP'; exfalso.
+ have BACK: backlogged job_arrival job_cost sched j_hp' t.
+ { apply/andP; split.
+  apply/andP; split. unfold arrived_before, has_arrived in *. by rewrite ltnW.
+ apply/negP; intro COMP; apply NOTCOMP'.
+ by apply completion_monotonic with (t0 := t).
+  apply/negP; intro SCHED'.
+ apply only_one_job_scheduled with (j1 := j_hp) in SCHED'; last by done.
+ by apply NOTHP; subst.
+ }
+ feed (PRIO j_hp' j_hp t PREEMPTP IN BACK); first by done.
+ by apply NOTHP; apply H_priority_is_transitive with j_hp'.
+ }
+ {
+ unfold quiet_time in *.
+ feed (NOTQUIET t.+1). apply/andP; split.
+  by apply leq_ltn_trans with t1.
+  rewrite subn1 ltn_subRL addnC in LTt2m1.
+ by rewrite [t.+1]addn1.
+ apply NOTQUIET.
+ unfold quiet_time in *; intros j_hp' IN HP ARR.
+ apply contraT; move => /negP NOTCOMP'; exfalso.
+ have BACK: backlogged job_arrival job_cost sched j_hp' t.
+ { apply/andP; split; last first.
+ { apply/negP; intro SCHED'.
+ apply only_one_job_scheduled with (j1 := j_hp) in SCHED'; last by done.
+ apply NOTHP.
+ by subst.
+ }
+ apply/andP; split. unfold arrived_before, has_arrived in *. by done.
+ apply/negP; intro COMP; apply NOTCOMP'.
+ by apply completion_monotonic with (t0 := t).
+ }
+ feed (PRIO j_hp' j_hp t PREEMPTP IN BACK); first by done.
+ by apply NOTHP; apply H_priority_is_transitive with j_hp'.
+ }
+ }
+ repeat split; [ by done  by done].
+ move: (SCHED) => PENDING.
+ eapply scheduled_implies_pending with (job_cost0 := job_cost) in PENDING; [ by eauto  by done].
+ apply/andP; split; last by apply leq_ltn_trans with (n := t); first by move: PENDING => /andP [ARR _].
+ apply contraT; rewrite ltnNge; intro LT; exfalso.
+ feed (QUIET j_hp); first by eapply CONS, SCHED.
+ specialize (QUIET HP LT).
+ have COMP: job_completed_by j_hp t by apply completion_monotonic with (t0 := t1).
+ apply completed_implies_not_scheduled in COMP; last by done.
+ by move: COMP => /negP COMP; apply COMP.
+ Qed.
+
+ (* In addition, we prove that every nonpreemptive segment
+ always begins with a preemption time. *)
+ Lemma scheduling_of_any_segment_starts_with_preemption_time:
+ forall j t,
+ job_scheduled_at j t >
+ exists pt,
+ job_arrival j <= pt <= t /\
+ preemption_time pt /\
+ (forall t', pt <= t' <= t > job_scheduled_at j t').
+ Proof.
+ intros s t SCHEDst.
+ have EX: exists t',
+ (t' <= t)
+ && (job_scheduled_at s t')
+ && (all (fun t'' => job_scheduled_at s t'') (iota t' (t  t').+1 )).
+ { exists t.
+ apply/andP; split; [ by apply/andP; split  ].
+ apply/allP; intros t'.
+ rewrite mem_iota.
+ rewrite subnn addn1 ltnS eqn_leq.
+ by move => /eqP EQ; subst t'. }
+ have MIN := ex_minnP EX.
+ move: MIN => [mpt /andP [/andP [LT1 SCHEDsmpt] /allP ALL] MIN]; clear EX.
+ destruct mpt.
+ { exists 0; repeat split.
+  apply/andP; split; last by done.
+ by apply H_jobs_must_arrive_to_execute in SCHEDsmpt.
+  by eapply zero_is_pt; eauto 2.
+  by intros; apply ALL; rewrite mem_iota subn0 add0n ltnS. }
+ { have NSCHED: ~~ job_scheduled_at s mpt.
+ { apply/negP; intros SCHED.
+ feed (MIN mpt).
+ apply/andP; split; [by apply/andP; split; [ apply ltnW  ]  ].
+ apply/allP; intros t'.
+ rewrite mem_iota addnS ltnS.
+ move => /andP [GE LE].
+ move: GE; rewrite leq_eqVlt; move => /orP [/eqP EQ LT].
+ subst t'. by done.
+ apply ALL.
+ rewrite mem_iota addnS ltnS.
+ apply/andP; split; first by done.
+ apply leq_trans with (mpt + (t  mpt)); first by done.
+ rewrite !subnKC; last rewrite ltnW; by done.
+ by rewrite ltnn in MIN. }
+ have PP: preemption_time mpt.+1.
+ { apply first_moment_is_pt with (arr_seq0 := arr_seq) (j0 := s); eauto 2. }
+ exists mpt.+1; repeat split; try done.
+  apply/andP; split; last by done.
+ by apply H_jobs_must_arrive_to_execute in SCHEDsmpt.
+  move => t' /andP [GE LE].
+ apply ALL; rewrite mem_iota.
+ rewrite addnS ltnS subnKC; last by done.
+ by apply/andP; split.
+ }
+ Qed.
+
+ (* Next we prove that at any time instant after a preemption point the
+ processor is always busy with a job with higher or equal priority. *)
+ Lemma not_quiet_implies_exists_scheduled_hp_job_after_preemption_point:
+ forall tp t,
+ preemption_time tp >
+ t1 <= tp < t2 >
+ tp <= t < t2 >
+ exists j_hp,
+ arrived_between job_arrival j_hp t1 t.+1 /\
+ higher_eq_priority j_hp j /\
+ job_scheduled_at j_hp t.
+ Proof.
+ move: (H_jobs_come_from_arrival_sequence) (H_work_conserving) => CONS WORK.
+ move: (H_respects_policy) => PRIO.
+ move => tp t PRPOINT /andP [GEtp LTtp] /andP [LEtp LTt].
+ have NOTIDLE := not_quiet_implies_not_idle
+ job_arrival job_cost arr_seq _ sched higher_eq_priority
+ j _ _ _ _ _ t1 t2 _ t.
+ feed_n 8 NOTIDLE; eauto 2.
+ apply/andP; split; [by apply leq_trans with tp  by done].
+ destruct (sched t) as [j_hp] eqn:SCHED;
+ last by exfalso; apply NOTIDLE; rewrite /is_idle SCHED.
+ move: SCHED => /eqP SCHED.
+ exists j_hp.
+ have HP: higher_eq_priority j_hp j.
+ { intros.
+ have SOAS := scheduling_of_any_segment_starts_with_preemption_time _ _ SCHED.
+ move: SOAS => [prt [/andP [_ LE] [PR SCH]]].
+ case E:(t1 <= prt).
+  move: E => /eqP /eqP E; rewrite subn_eq0 in E.
+ have EXISTS := not_quiet_implies_exists_scheduled_hp_job_at_preemption_point prt.
+ feed_n 2 EXISTS; try done.
+ { by apply /andP; split; last by apply leq_ltn_trans with t. }
+ move: EXISTS => [j_lp [_ [HEP SCHEDjhp]]].
+ have EQ: j_hp = j_lp.
+ { by apply (only_one_job_scheduled sched _ _ prt); first (apply SCH; apply/andP; split). }
+ by subst j_hp.
+  move: E => /eqP /neqP E; rewrite lt0n subn_gt0 in E.
+ apply negbNE; apply/negP; intros LP.
+ rename j_hp into j_lp.
+ have EXISTS := not_quiet_implies_exists_scheduled_hp_job_at_preemption_point tp.
+ feed_n 2 EXISTS; try done.
+ { by apply /andP; split. }
+ move: EXISTS => [j_hp [_ [HEP SCHEDjhp]]].
+ have EQ: j_hp = j_lp.
+ { apply (only_one_job_scheduled sched _ _ tp).
+ by done.
+ apply SCH; apply/andP; split.
+ apply leq_trans with t1. rewrite ltnW //. by done.
+ by done.
+ }
+ by subst j_hp; move: LP => /negP LP; apply: LP.
+ }
+ repeat split; [ by done  by done].
+ move: (H_busy_interval_prefix) => [SL [QUIET [NOTQUIET EXj]]].
+ move: (SCHED) => PENDING.
+ eapply scheduled_implies_pending with (job_cost0 := job_cost) in PENDING;
+ [ by eauto  by done].
+ apply/andP; split;
+ last by apply leq_ltn_trans with (n := t); first by move: PENDING => /andP [ARR _].
+ apply contraT; rewrite ltnNge; intro LT; exfalso.
+ feed (QUIET j_hp); first by eapply CONS, SCHED.
+ specialize (QUIET HP LT).
+ have COMP: job_completed_by j_hp t.
+ { by apply completion_monotonic with (t0 := t1); [ apply leq_trans with tp  ]. }
+ apply completed_implies_not_scheduled in COMP; last by done.
+ by move: COMP => /negP COMP; apply COMP.
+ Qed.
+
+ (* Now, suppose there exists some constant K that bounds the distance to
+ a preemption time from the beginning of the busy interval. *)
+ Variable K: time.
+ Hypothesis H_preemption_time_exists:
+ exists pr_t, preemption_time pr_t /\ t1 <= pr_t <= t1 + K.
+
+ (* Then we prove that the processor is always busy with a job with
+ higherorequal priority after time instant [t1 + K]. *)
+ Lemma not_quiet_implies_exists_scheduled_hp_job:
+ forall t,
+ t1 + K <= t < t2 >
+ exists j_hp,
+ arrived_between job_arrival j_hp t1 t.+1 /\
+ higher_eq_priority j_hp j /\
+ job_scheduled_at j_hp t.
+ Proof.
+ move => t /andP [GE LT].
+ move: H_preemption_time_exists => [prt [PR /andP [GEprt LEprt]]].
+ apply not_quiet_implies_exists_scheduled_hp_job_after_preemption_point with (tp := prt); eauto 2.
+  apply/andP; split; first by done.
+ apply leq_ltn_trans with (t1 + K); first by done.
+ by apply leq_ltn_trans with t.
+  apply/andP; split; last by done.
+ by apply leq_trans with (t1 + K).
+ Qed.
+
+ End PreemptionTimeAndPriorityInversion.
+
+ (* In this section we prove that the function max_length_of_priority_inversion
+ indeed upper bounds the priority inversion length. *)
+ Section PreemprionTimeExists.
+
+ (* First we prove that if a job with higherorequal priority is scheduled at
+ a quiet time t+1 then this is the first time when this job is scheduled. *)
+ Lemma hp_job_not_scheduled_before_quiet_time:
+ forall jhp t,
+ quiet_time job_arrival job_cost arr_seq sched higher_eq_priority j t.+1 >
+ job_scheduled_at jhp t.+1 >
+ higher_eq_priority jhp j >
+ ~~ job_scheduled_at jhp t.
+ Proof.
+ intros jhp t QT SCHED1 HP.
+ apply/negP; intros SCHED2.
+ specialize (QT jhp).
+ feed_n 3 QT; try done.
+ eapply H_jobs_come_from_arrival_sequence; eauto 1.
+ rewrite /arrived_before ltnS.
+ apply H_jobs_must_arrive_to_execute. by done.
+ apply completed_implies_not_scheduled in QT; last by done.
+ by move: QT => /negP NSCHED; apply: NSCHED.
+ Qed.
+
+ (* Also, we show that lowerpriority jobs that are scheduled inside the
+ busyinterval prefix [t1,t2) must have arrived before that interval. *)
+ Lemma low_priority_job_arrives_before_busy_interval_prefix:
+ forall jlp t,
+ t1 <= t < t2 >
+ job_scheduled_at jlp t >
+ ~~ higher_eq_priority jlp j >
+ job_arrival jlp < t1.
+ Proof.
+ move => jlp t /andP [GE LT] SCHED LP.
+ move: (H_busy_interval_prefix) => [NEM [QT [NQT HPJ]]].
+ apply negbNE; apply/negP; intros ARR; rewrite leqNgt in ARR.
+ have SCH:= scheduling_of_any_segment_starts_with_preemption_time _ _ SCHED.
+ move: SCH => [pt [/andP [NEQ1 NEQ2] [PT FA]]].
+ have NEQ: t1 <= pt < t2.
+ { apply/andP; split.
+ apply leq_trans with (job_arrival jlp); by done.
+ apply leq_ltn_trans with t; by done. }
+ have LL:= not_quiet_implies_exists_scheduled_hp_job_at_preemption_point pt.
+ feed_n 2 LL; try done.
+ move: LL => [jhp [ARRjhp [HP SCHEDhp]]].
+ feed (FA pt). apply/andP; split; by done.
+ have OOJ:= only_one_job_scheduled _ _ _ _ FA SCHEDhp; subst jhp.
+ by move: LP => /negP LP; apply: LP.
+ Qed.
+
+ (* Moreover, we show that lowerpriority jobs that are scheduled inside the
+ busyinterval prefix [t1,t2) must be scheduled before that interval. *)
+ Lemma low_priority_job_scheduled_before_busy_interval_prefix:
+ forall jlp t,
+ t1 <= t < t2 >
+ job_scheduled_at jlp t >
+ ~~ higher_eq_priority jlp j >
+ exists t', t' < t1 /\ job_scheduled_at jlp t'.
+ Proof.
+ move => jlp t NEQ SCHED LP.
+ have ARR := low_priority_job_arrives_before_busy_interval_prefix _ _ NEQ SCHED LP.
+ move: NEQ => /andP [GE LT].
+ exists t1.1.
+ split.
+ { rewrite prednK; first by done.
+ by apply leq_ltn_trans with (job_arrival jlp).
+ }
+ { move: (H_busy_interval_prefix) => [NEM [QT [NQT HPJ]]].
+ have SCHEDST := scheduling_of_any_segment_starts_with_preemption_time _ _ SCHED.
+ move: SCHEDST => [pt [NEQpt [PT SCHEDc]]].
+ have NEQ: pt < t1.
+ { rewrite ltnNge; apply/negP; intros CONTR.
+ have NQSCHED := not_quiet_implies_exists_scheduled_hp_job_at_preemption_point pt.
+ feed_n 2 NQSCHED; try done.
+ { apply/andP; split; first by done.
+ by apply leq_ltn_trans with t; move: NEQpt => /andP [_ T].
+ }
+ move: NQSCHED => [jhp [ARRhp [HPhp SCHEDhp]]].
+ specialize (SCHEDc pt).
+ feed SCHEDc.
+ { by apply/andP; split; last move: NEQpt => /andP [_ T]. }
+ have EQ:= only_one_job_scheduled sched jhp jlp pt.
+ feed_n 2 EQ; try done.
+ subst jhp.
+ by move: LP => /negP LP; apply: LP.
+ }
+ apply SCHEDc; apply/andP; split.
+  rewrite addn1 in NEQ.
+ apply subh3 in NEQ.
+ by rewrite subn1 in NEQ.
+  apply leq_trans with t1. by apply leq_pred. by done.
+ }
+ Qed.
+
+ (* Thus, there must be a preemption time in the interval [t1, t1 + max_priority_inversion t1].
+ That is, if a job with higherorequal priority is scheduled at time instant t1, then t1 is
+ a preemprion time. Otherwise, if a job with lower priority is scheduled at time t1,
+ then this jobs also should be scheduled before the beginning of the busy interval. So, the
+ next preemption time will be no more than [max_priority_inversion t1] time units later. *)
+ Lemma preemption_time_exists:
+ exists pr_t,
+ preemption_time pr_t /\
+ t1 <= pr_t <= t1 + max_length_of_priority_inversion j t1.
+ Proof.
+ set (service := service sched).
+ move: (H_correct_preemption_model) => CORR.
+ move: (H_busy_interval_prefix) => [NEM [QT1 [NQT HPJ]]].
+ case SCHED: (sched t1) => [s  ]; move: SCHED => /eqP SCHED; last first.
+ { exists t1; split; last first.
+ apply/andP; split; [by done  by rewrite leq_addr].
+ move: SCHED => /eqP SCHED.
+ rewrite /preemption_time /LimitedPreemptionPlatform.preemption_time.
+ by rewrite SCHED.
+ }
+ { case PRIO: (higher_eq_priority s j).
+ { exists t1; split; last first.
+ apply/andP; split; [by done  by rewrite leq_addr].
+ destruct t1.
+ { eapply zero_is_pt; [eauto 2  apply H_jobs_come_from_arrival_sequence]. }
+ eapply hp_job_not_scheduled_before_quiet_time in QT1; eauto 2.
+ eapply first_moment_is_pt with (j0 := s); eauto 2.
+ }
+ { move: (SCHED) => ARRs; apply H_jobs_come_from_arrival_sequence in ARRs.
+ move: (H_model_with_bounded_nonpreemptive_segments s ARRs) => [_ [_ [_ EXPP]]].
+ move: (EXPP (service s t1)) => PP; clear EXPP.
+ feed PP. by apply/andP; split; [done  apply H_completed_jobs_dont_execute].
+ have EX: exists pt,
+ ((service s t1) <= pt <= (service s t1) + (job_max_nps s  1))
+ && can_be_preempted s pt.
+ { move: PP => [pt [NEQ PP]].
+ exists pt; apply/andP; split; by done.
+ } clear PP.
+ have MIN := ex_minnP EX.
+ move: MIN => [sm_pt /andP [NEQ PP] MIN]; clear EX.
+ have Fact: exists Δ, sm_pt = service s t1 + Δ.
+ { exists (sm_pt  service s t1).
+ apply/eqP; rewrite eq_sym; apply/eqP; rewrite subnKC //.
+ by move: NEQ => /andP [T _]. }
+ move: Fact => [Δ EQ]; subst sm_pt; rename Δ into sm_pt.
+ exists (t1 + sm_pt); split.
+ { have Fact1:
+ forall prog, service s t1 <= prog < service s t1 + sm_pt >
+ ~~ can_be_preempted s prog.
+ { move => prog /andP [GE LT].
+ apply/negP; intros PPJ.
+ feed (MIN prog); first (apply/andP; split); try done.
+  apply/andP; split; first by done.
+ apply leq_trans with (service s t1 + sm_pt).
+ + by apply ltnW.
+ + by move: NEQ => /andP [_ K].
+  by move: MIN; rewrite leqNgt; move => /negP NLT; apply: NLT.
+ }
+ have Fact2: forall t', t1 <= t' < t1 + sm_pt > job_scheduled_at s t'.
+ {
+ move => t' /andP [GE LT].
+ have Fact: exists Δ, t' = t1 + Δ.
+ { by exists (t'  t1); apply/eqP; rewrite eq_sym; apply/eqP; rewrite subnKC. }
+ move: Fact => [Δ EQ]; subst t'.
+ move: (Fact1 (service s (t1 + Δ)))(CORR s) => NPPJ T.
+ feed T; first by done. move: T => [T _ ].
+ apply: T; apply: NPPJ.
+ apply/andP; split.
+ { by apply Service.service_monotonic; rewrite leq_addr. }
+ rewrite /service /UniprocessorSchedule.service (@Service.service_during_cat _ _ _ t1).
+ { rewrite ltn_add2l; rewrite ltn_add2l in LT.
+ apply leq_ltn_trans with Δ; last by done.
+ rewrite {2}(sum_of_ones t1 Δ).
+ rewrite leq_sum //; clear; intros t _.
+ by rewrite /service_at; destruct (scheduled_at sched s t). }
+ { by apply/andP; split; [done  rewrite leq_addr]. }
+ }
+ rewrite /preemption_time /LimitedPreemptionPlatform.preemption_time.
+ case SCHEDspt: (sched (t1 + sm_pt)) => [s0  ]; last by done.
+ move: SCHEDspt => /eqP SCHEDspt.
+ destruct (s == s0) eqn: EQ.
+ { move: EQ => /eqP EQ; subst s0.
+ rewrite /UniprocessorSchedule.service.
+ rewrite (@Service.service_during_cat _ _ _ t1); last first.
+ { by apply/andP; split; [ done  rewrite leq_addr]. }
+ have ALSCHED: service_during sched s t1 (t1 + sm_pt) = sm_pt.
+ { rewrite {2}(sum_of_ones t1 sm_pt) /service_during.
+ apply/eqP; rewrite eqn_leq //; apply/andP; split.
+ { rewrite leq_sum //; clear; intros t _.
+ by unfold service_at; destruct (scheduled_at sched s t). }
+ { rewrite big_nat_cond [in X in _ <= X]big_nat_cond.
+ rewrite leq_sum //.
+ move => x /andP [HYP _].
+ rewrite lt0b.
+ by apply Fact2.
+ }
+ }
+ by rewrite ALSCHED.
+ }
+ destruct sm_pt.
+ { exfalso; move: EQ => /negP EQ; apply: EQ.
+ move: SCHED SCHEDspt => /eqP SCHED /eqP SCHEDspt.
+ rewrite addn0 in SCHEDspt; rewrite SCHEDspt in SCHED.
+ by inversion SCHED. }
+ { rewrite addnS.
+ move: (H_correct_preemption_model s0) => T.
+ feed T; first by eauto 2. move: T => [_ T]; apply: T.
+ apply /negP; intros CONTR.
+ move: EQ => /negP EQ; apply: EQ.
+ move: (Fact2 (t1 + sm_pt)) => SCHEDs0.
+ feed SCHEDs0; first by apply/andP; split; [rewrite leq_addr  rewrite addnS].
+ apply/eqP; eapply only_one_job_scheduled; eauto 2.
+ by rewrite addnS.
+ }
+ }
+ move: NEQ => /andP [GE LE].
+ apply/andP; split; first by rewrite leq_addr.
+ rewrite leq_add2l.
+ unfold max_length_of_priority_inversion.
+ rewrite (big_rem s) //=.
+ { rewrite PRIO; simpl.
+ apply leq_trans with (job_max_nps s  ε); last by rewrite leq_maxl.
+ by rewrite leq_add2l in LE. }
+ eapply arrived_between_implies_in_arrivals; eauto 2.
+ apply/andP; split; first by done.
+ eapply low_priority_job_arrives_before_busy_interval_prefix with t1; eauto 2.
+ by rewrite PRIO.
+ }
+ }
+ Qed.
+
+ End PreemprionTimeExists.
+
+ End PriorityInversionIsBounded.
+
+End PriorityInversionIsBounded.
\ No newline at end of file
diff git a/model/schedule/uni/limited/platform/util.v b/model/schedule/uni/limited/platform/util.v
new file mode 100644
index 0000000000000000000000000000000000000000..30054fc7848d891c27338b07b966586bd5ddc3ec
 /dev/null
+++ b/model/schedule/uni/limited/platform/util.v
@@ 0,0 +1,684 @@
+Require Import rt.util.all.
+
+From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
+
+(** * Nondecreasing sequence *)
+(** In this module we introduce the notion of a nondecreasing sequence
+ that will be used to describe preemption points in models with limited preemptions. *)
+Module NondecreasingSequence.
+
+ (* First, let's introduce the notion of the nth element of a sequence. *)
+ Notation "xs [ n ]" := (nth 0 xs n) (at level 30).
+
+ (* In this section we provide the notion of a nondecreasing sequence. *)
+ Section Definitions.
+
+ (* We say that a sequence xs is nondecincreasing iff for any two indices n1 and n2
+ such that [n1 <= n2 < size xs] the following condition holds: xs[n1] <= xs[n2]. *)
+ Definition nondecreasing_sequence (xs: seq nat) :=
+ forall n1 n2,
+ n1 <= n2 < size xs >
+ nth 0 xs n1 <= nth 0 xs n2.
+
+ (* For a nondecreasing sequence we define the notion of
+ distances between neighboring elements of the sequence. *)
+ (* Example:
+ Consider the following sequence of natural numbers: xs = [:: 1; 10; 10; 17; 20; 41].
+ Then [drop 1 xs] is equal to [:: 10; 10; 17; 20; 41].
+ Then [zip xs (drop 1 xs)] is equal to [:: (1,10); (10,10); (10,17); (17,20); (20,41)]
+ And after the mapping [map (fun '(x1, x2) => x2  x1)] we end up with [:: 9; 0; 7; 3; 21]. *)
+ Definition distances (xs: seq nat) :=
+ map (fun '(x1, x2) => x2  x1) (zip xs (drop 1 xs)).
+
+ (* Next, we define some common operations on lists.
+ Namely max, first, and last. *)
+ Definition max := foldl maxn 0.
+ Definition first := head 0.
+ Definition last := last 0.
+
+ End Definitions.
+
+ (* In this section, we prove a few basic lemmas about nondecreasing sequences. *)
+ Section Lemmas.
+
+ (* Next, we prove that no element can lie strictly between two
+ neighboring elements and still belong to the list. *)
+ Lemma antidensity_of_nondecreasing_seq:
+ forall (xs: seq nat) (x: nat) (n: nat),
+ nondecreasing_sequence xs >
+ xs [ n ] < x < xs [ n.+1 ] >
+ ~~ (x \in xs).
+ Proof.
+ clear.
+ intros ? ? ? STR ?; apply/negP; intros ?.
+ move: H0 => /nthP. intros GG.
+ specialize (GG 0).
+ move: GG => [ind LE HHH].
+ subst x; rename ind into x.
+ destruct (n.+1 < size xs) eqn:Bt; last first.
+ { move: Bt => /negP /negP; rewrite leqNgt; move => Bt.
+ apply nth_default with (x0 := 0) in Bt.
+ rewrite Bt in H; by move: H => /andP [_ T]. }
+ have B1: n.+1 < size xs; first by done. clear Bt.
+ have B2: n < size xs; first by apply leq_ltn_trans with n.+1.
+ have GT: n < x.
+ { move: H => /andP [T _].
+ rewrite ltnNge; apply/negP; intros CONTR.
+ specialize (STR x n).
+ feed STR. by apply/andP; split.
+ by move: STR; rewrite leqNgt; move => /negP STR; apply: STR.
+ }
+ have LT: x < n.+1.
+ { clear GT.
+ move: H => /andP [_ T].
+ rewrite ltnNge; apply/negP; intros CONTR.
+ move: CONTR; rewrite leq_eqVlt; move => /orP [/eqP EQ  CONTR].
+ { by subst; rewrite ltnn in T. }
+ specialize (STR n.+1 x).
+ feed STR. by apply/andP; split; [ apply ltnW  done].
+ by move: STR; rewrite leqNgt; move => /negP STR; apply: STR.
+ }
+ by move: LT; rewrite ltnNge; move => /negP LT; apply: LT.
+ Qed.
+
+ (* Alternatively, consider an arbitrary natural number x that is
+ bounded by the first and the last element of a sequence xs. Then
+ there is an index n such that xs[n] <= x < x[n+1]. *)
+ Lemma belonging_to_segment_of_seq_is_total:
+ forall (xs: seq nat) (x: nat),
+ 2 <= size xs >
+ first xs <= x < last xs >
+ exists n,
+ n.+1 < size xs /\
+ xs[n] <= x < xs[n.+1].
+ Proof.
+ clear; intros ? ? SIZE LAST.
+ have EX: exists n, size xs <= n.
+ { by exists (size xs). } move: EX => [n LE].
+ destruct n.
+ { intros; destruct xs; by done. }
+ destruct n.
+ { intros.
+ destruct xs; first by done.
+ by destruct xs.
+ }
+ generalize dependent xs.
+ induction n.
+ { intros.
+ destruct xs; first by done.
+ destruct xs; first by done.
+ destruct xs; last by done.
+ clear LE SIZE.
+ by exists 0; unfold last in *; simpl in *.
+ }
+ { intros.
+ destruct xs; first by done.
+ destruct xs; first by done.
+ destruct xs.
+ { by exists 0; unfold last in *; simpl in *. }
+ destruct (x >= n1) eqn: NEQ.
+ { specialize (IHn [:: n1, n2 & xs]).
+ feed_n 3 IHn.
+ { by done. }
+ { move: LAST => /andP [LAST1 LAST2].
+ apply/andP; split; first by done.
+ apply leq_trans with (last [:: n0, n1, n2 & xs]); first by done.
+ by rewrite /last !last_cons.
+ }
+ { by rewrite (ltn_add2r 1) !addn1. }
+ move: IHn => [idx [SI /andP [G L]]].
+ exists idx.+1; split.
+  by simpl in *; rewrite addn1 [in X in _ <= X]addn1 leq_add2r.
+  by apply/andP; split.
+ }
+ { clear IHn SIZE LE; simpl in *.
+ exists 0; split; first by done.
+ move: NEQ => /negP /negP; rewrite ltnNge; move => NEQ.
+ move: LAST => /andP [LAST _].
+ by apply/andP; split.
+ }
+ }
+ Qed.
+
+ (* We prove that the difference between any two neighboring elements is
+ bounded by the max element of the distancessequence. *)
+ Lemma distance_between_neighboring_elements_le_max_distance_in_seq:
+ forall (xs: seq nat) (n: nat),
+ xs[n.+1]  xs[n] <= max (distances xs).
+ Proof.
+ clear; intros xs id.
+ apply leq_trans with (distances xs [ id ]).
+ rewrite leq_eqVlt; apply/orP; left; apply/eqP.
+ have EX: exists n, size xs <= n.
+ { by exists (size xs). } move: EX => [n LE].
+ generalize dependent xs; generalize dependent id.
+ induction n.
+ { intros.
+ move: LE; rewrite leqn0 size_eq0; move => /eqP EQ; subst.
+ by rewrite !nth_default.
+ }
+ { intros.
+ move: LE; rewrite leq_eqVlt; move => /orP [/eqP EQLT]; last first.
+ { by apply IHn; rewrite ltnS in LT. }
+ destruct xs; first by done.
+ destruct xs; first by destruct id; [simpl rewrite !nth_default].
+ have Fact: distances [:: n0, n1 & xs] = (n1  n0) :: distances [:: n1 & xs].
+ { by rewrite /distances; simpl; rewrite drop0. }
+ rewrite Fact; clear Fact.
+ destruct id; first by done.
+ simpl.
+ rewrite IHn. simpl. by done.
+ by move: EQ => /eqP; simpl; rewrite eqSS; move => /eqP EQ; rewrite EQ.
+ }
+ {
+ have Lem: forall x xs, x \in xs > x <= max xs.
+ { clear; intros.
+ generalize dependent x.
+ induction xs.
+ { by done. }
+ { intros ? IN; rewrite /max seq_max_cons leq_max; apply/orP.
+ move: IN; rewrite in_cons; move => /orP [/eqP EQ IN].
+  by left; subst.
+  by right; apply IHxs.
+ }
+ }
+ destruct (size (distances xs) <= id) eqn:SIZE.
+ { by rewrite nth_default. }
+ { apply Lem; rewrite mem_nth //.
+ move: SIZE => /negP /negP.
+ by rewrite ltnNge.
+ }
+ }
+ Qed.
+
+ (* As a corollary, the max distance between elements of any nontrivial sequence
+ (i.e. a sequence that contains at leas two distinct elements) is positive. *)
+ Corollary max_distance_in_nontrivial_seq_is_positive:
+ forall (xs: seq nat),
+ nondecreasing_sequence xs >
+ (exists x y, x \in xs /\ y \in xs /\ x <> y) >
+ 0 < max (distances xs).
+ Proof.
+ clear.
+ intros xs SIZE SMI.
+ move: SMI => [x [y [INx [INy NEQ]]]].
+ move: INx INy => /nthP INx /nthP INy.
+ specialize (INx 0); specialize (INy 0).
+ move: INx INy => [indx SIZEx EQx] [indy SIZEy EQy].
+ move: NEQ => /eqP; rewrite neq_ltn; move => /orP [LTLT].
+ { have LTind: indx < indy.
+ { rewrite ltnNge; apply/negP; intros CONTR.
+ specialize (SIZE indy indx).
+ feed SIZE; first by apply/andP; split.
+ subst x y.
+ by move: SIZE; rewrite leqNgt; move => /negP T; apply: T.
+ }
+ have EQ: exists Δ, indy = indx + Δ.
+ { exists (indy  indx). by rewrite subnKC; last apply ltnW. }
+ move: EQ => [Δ EQ]; subst indy.
+ have F: exists ind, indx <= ind < indx + Δ /\ xs[ind] < xs[ind.+1].
+ { subst x y.
+ clear SIZEx SIZEy.
+ generalize dependent xs.
+ generalize dependent indx.
+ induction Δ.
+ { intros.
+ exfalso.
+ by move: LT; rewrite addn0 ltnn.
+ }
+ intros.
+ have ALT: Δ = 0 \/ Δ > 0.
+ { by destruct Δ; auto. }
+ move: ALT => [ZERO  POS].
+ { subst Δ.
+ exists indx; split; last by rewrite addn1 in LT.
+ by rewrite addn1; apply/andP; split.
+ }
+ have ALT: xs[indx + Δ] == xs[indx + Δ.+1] \/ xs[indx + Δ] < xs[indx + Δ.+1].
+ { rewrite addnS.
+ have NEQ: xs [indx + Δ] <= xs [(indx + Δ).+1].
+ apply SIZE; apply/andP; split; first by done.
+ rewrite ltnNge; apply/negP; intros CONTR.
+ move: LT; rewrite ltnNge; move => /negP LT; apply: LT.
+ have EQ: xs [indx + Δ.+1] = 0.
+ { by rewrite nth_default ?addnS. }
+ by rewrite EQ; clear EQ.
+ by apply/orP; rewrite leq_eqVlt.
+ }
+ move: ALT => [/eqP EQLT'].
+ { specialize (IHΔ indx).
+ feed IHΔ; first by rewrite addn1 leq_add2l.
+ rewrite EQ in LT.
+ specialize (IHΔ xs SIZE LT).
+ move: IHΔ => [ind [/andP [B1 B2] UP]].
+ exists ind; split; last by done.
+ apply/andP; split; first by done.
+ by rewrite addnS ltnS ltnW.
+ }
+ { exists (indx + Δ); split.
+  apply/andP; split; first by rewrite leq_addr.
+ by rewrite addnS.
+  by rewrite addnS.
+ }
+ }
+ move: F => [ind [/andP [B1 B2] UP]].
+ apply leq_trans with (xs [ind.+1]  xs [ind]).
+  by rewrite subn_gt0.
+  by apply distance_between_neighboring_elements_le_max_distance_in_seq.
+ }
+ { have LTind: indy < indx.
+ { rewrite ltnNge; apply/negP; intros CONTR.
+ specialize (SIZE indx indy).
+ feed SIZE; first by apply/andP; split.
+ subst x y.
+ by move: SIZE; rewrite leqNgt; move => /negP T; apply: T.
+ }
+ have EQ: exists Δ, indx = indy + Δ.
+ { exists (indx  indy). by rewrite subnKC; last apply ltnW. }
+ move: EQ => [Δ EQ]; subst indx.
+ have F: exists ind, indy <= ind < indy + Δ /\ xs[ind] < xs[ind.+1].
+ { subst x y.
+ clear SIZEx SIZEy.
+ generalize dependent xs.
+ generalize dependent indy.
+ induction Δ.
+ { intros.
+ exfalso.
+ by move: LT; rewrite addn0 ltnn.
+ }
+ intros.
+ have ALT: Δ = 0 \/ Δ > 0.
+ { by destruct Δ; auto. }
+ move: ALT => [ZERO  POS].
+ { subst Δ.
+ exists indy; split; last by rewrite addn1 in LT.
+ by rewrite addn1; apply/andP; split.
+ }
+ have ALT: xs[indy + Δ] == xs[indy + Δ.+1] \/ xs[indy + Δ] < xs[indy + Δ.+1].
+ { rewrite addnS.
+ have NEQ: xs [indy + Δ] <= xs [(indy + Δ).+1].
+ apply SIZE; apply/andP; split; first by done.
+ rewrite ltnNge; apply/negP; intros CONTR.
+ move: LT; rewrite ltnNge; move => /negP LT; apply: LT.
+ have EQ: xs [indy + Δ.+1] = 0.
+ { by rewrite nth_default ?addnS. }
+ by rewrite EQ; clear EQ.
+ by apply/orP; rewrite leq_eqVlt.
+ }
+ move: ALT => [/eqP EQLT'].
+ { specialize (IHΔ indy).
+ feed IHΔ; first by rewrite addn1 leq_add2l.
+ rewrite EQ in LT.
+ specialize (IHΔ xs SIZE LT).
+ move: IHΔ => [ind [/andP [B1 B2] UP]].
+ exists ind; split; last by done.
+ apply/andP; split; first by done.
+ by rewrite addnS ltnS ltnW.
+ }
+ { exists (indy + Δ); split.
+  apply/andP; split; first by rewrite leq_addr.
+ by rewrite addnS.
+  by rewrite addnS.
+ }
+ }
+ move: F => [ind [/andP [B1 B2] UP]].
+ apply leq_trans with (xs [ind.+1]  xs [ind]).
+  by rewrite subn_gt0.
+  by apply distance_between_neighboring_elements_le_max_distance_in_seq.
+ }
+ Qed.
+
+ (* Note that the distancesfunction has the expected behavior indeed. I.e. an element
+ on the nth position of the distancesequence is equal to the difference between
+ n+1th and nth elements. *)
+ Lemma function_of_distances_is_correct:
+ forall (xs: seq nat) (n: nat),
+ (distances xs)[n] = xs[n.+1]  xs[n].
+ Proof.
+ clear.
+ intros xs.
+ have EX: exists len, size xs <= len.
+ { exists (size xs). by done. }
+ move: EX => [len LE].
+ generalize dependent xs.
+ induction len.
+ { intros.
+ move: LE; rewrite leqn0 size_eq0; move => /eqP EQ; subst.
+ unfold distances. simpl.
+ by destruct n; simpl.
+ }
+ intros.
+ move: LE; rewrite leq_eqVlt; move => /orP [/eqP EQ LE]; last first.
+ { by apply IHlen. }
+ destruct xs as [  x1 xs]. inversion EQ.
+ destruct xs as [  x2 xs].
+ { clear EQ.
+ destruct n. by simpl.
+ destruct n; by simpl.
+ }
+ destruct n; first by done.
+ have F: distances [:: x1, x2 & xs] [n.+1] = distances [::x2 & xs] [ n ].
+ { have EQ': distances [:: x1, x2 & xs] = (x2  x1) :: distances [::x2 & xs].
+ { by unfold distances; simpl; rewrite drop0. }
+ by rewrite EQ'.
+ }
+ have F2: [:: x1, x2 & xs] [n.+2]  [:: x1, x2 & xs] [n.+1] = [:: x2 & xs] [n.+1]  [:: x2 & xs] [n]; first by done.
+ rewrite F F2.
+ apply IHlen.
+ move: EQ => /eqP; simpl; rewrite eqSS; move => /eqP EQ.
+ by rewrite EQ.
+ Qed.
+
+ (* We show that the size of a distancessequence is one less
+ than the size of the original sequence. *)
+ Lemma size_of_seq_of_distances:
+ forall (xs: seq nat),
+ 2 <= size xs >
+ size xs = size (distances xs) + 1.
+ Proof.
+ clear.
+ intros xs.
+ have EX: exists len, size xs <= len.
+ { exists (size xs). by done. }
+ move: EX => [len LE].
+ generalize dependent xs.
+ induction len.
+ { intros.
+ move: LE; rewrite leqn0 size_eq0; move => /eqP EQ; subst.
+ by done.
+ }
+ intros ? ? SIZE.
+ move: LE; rewrite leq_eqVlt; move => /orP [/eqP EQ LE]; last first.
+ { by apply IHlen. }
+ destruct xs as [  x1 xs]; first by inversion EQ.
+ destruct xs as [  x2 xs]; first by inversion SIZE.
+ destruct xs as [  x3 xs]; first by done.
+ clear SIZE.
+ have F1: size [:: x1, x2, x3 & xs] = size [:: x2, x3 & xs] + 1.
+ { by rewrite addn1. }
+ have F2: size (distances [:: x1, x2, x3 & xs]) = size (distances [:: x2, x3 & xs]) + 1.
+ { by rewrite addn1. }
+ rewrite F1 F2; clear F1 F2.
+ apply/eqP; rewrite eqn_add2r; apply/eqP.
+ apply IHlen.
+ { move: EQ => /eqP. simpl. rewrite eqSS; move => /eqP EQ.
+ by rewrite EQ.
+ }
+ by done.
+ Qed.
+
+ (* Note that the last element of a nondecreasing sequence is the max element. *)
+ Lemma last_is_max_in_nondecreasing_seq:
+ forall (xs: seq nat) (x: nat),
+ nondecreasing_sequence xs >
+ (x \in xs) >
+ x <= last xs.
+ Proof.
+ clear; intros ? ? STR IN.
+ have NEQ: forall x y, x = y \/ x != y.
+ { clear. intros.
+ destruct (x == y) eqn:EQ.
+  by left; apply/eqP.
+  by right.
+ }
+ move: (NEQ _ x (last xs)); clear NEQ; move => [EQNEQ].
+ { by subst x. }
+ move: IN => /nthP EX.
+ specialize (EX 0).
+ move: EX => [id SIZE EQ].
+ rewrite /last nth_last EQ; subst x.
+ rewrite addn1 in SIZE.
+ apply STR; apply/andP.
+ have POS: 0 < size xs.
+ { by apply leq_trans with (id + 1); [rewrite addn1 done]. }
+ split.
+  by rewrite (leq_add2r 1) !addn1 prednK // addn1.
+  by rewrite prednK.
+ Qed.
+
+ (* Given a nondecreasing sequence xs with length n, we show that the difference
+ between the last element of xs and the last element of the distancessequence
+ of xs is equal to the (n2)'th element of xs. *)
+ Lemma last_seq_minus_last_distance_seq:
+ forall (xs: seq nat),
+ nondecreasing_sequence xs >
+ last xs  last (distances xs) = xs [ (size xs).2 ].
+ Proof.
+ clear.
+ intros xs SIS.
+ destruct xs as [  x1 xs]. unfold last, seq.last. simpl. by done.
+ destruct xs as [  x2 xs]. unfold last, seq.last. simpl. by rewrite subn0.
+ rewrite {2}/last [in X in _  X]nth_last function_of_distances_is_correct prednK; last by done.
+ set [:: x1, x2 & xs] as X.
+ rewrite /last nth_last.
+ rewrite size_of_seq_of_distances; last by done.
+ rewrite !addn1.
+ rewrite pred_Sn.
+ rewrite subKn; first by done.
+ unfold X.
+ unfold nondecreasing_sequence in *.
+ apply SIS.
+ apply/andP; split.
+ simpl; by done.
+ rewrite [in X in _ < X]size_of_seq_of_distances; last by done.
+ by rewrite addn1.
+ Qed.
+
+ (* Note that the last element is at most the max element. *)
+ Lemma last_of_seq_le_max_of_seq:
+ forall (xs: seq nat),
+ last xs <= max xs.
+ Proof.
+ clear.
+ intros xs.
+ have EX: exists len, size xs <= len.
+ { exists (size xs). by done. }
+ move: EX => [len LE].
+ generalize dependent xs.
+ induction len.
+ { by intros; move: LE; rewrite leqn0 size_eq0; move => /eqP EQ; subst. }
+ intros ? SIZE.
+ move: SIZE; rewrite leq_eqVlt; move => /orP [/eqP EQ LE]; last first.
+ { by apply IHlen. }
+ destruct xs as [  x1 xs]; first by inversion EQ.
+ destruct xs as [  x2 xs]. by rewrite /last /max leq_max; apply/orP; right.
+ have F1: last [:: x1, x2 & xs] = last [:: x2 & xs].
+ { by unfold last; simpl. }
+ rewrite F1 /max seq_max_cons; clear F1.
+ rewrite leq_max; apply/orP; right.
+ apply IHlen.
+ move: EQ => /eqP; simpl; rewrite eqSS; move => /eqP EQ.
+ by subst.
+ Qed.
+
+ (* If any n'th element of a sequence xs is lessthanorequalto n'th
+ element of ys, then max of xs is lessthanorequalto max of ys. *)
+ Lemma max_of_dominating_seq:
+ forall (xs ys: seq nat),
+ (forall n, xs[n] <= ys[n]) >
+ max xs <= max ys.
+ Proof.
+ clear.
+ intros xs ys.
+ have EX: exists len, size xs <= len /\ size ys <= len.
+ { exists (maxn (size xs) (size ys)).
+ by split; rewrite leq_max; apply/orP; [left  right].
+ }
+ move: EX => [len [LE1 LE2]].
+ generalize dependent xs.
+ generalize dependent ys.
+ induction len.
+ { intros.
+ move: LE1 LE2; rewrite !leqn0 !size_eq0; move => /eqP E1 /eqP E2.
+ subst. by done.
+ }
+ {
+ intros.
+ destruct xs, ys; try done.
+ { have L: forall xs, (forall n, xs [ n ] = 0) > max xs = 0.
+ { clear. intros.
+ induction xs; first by done.
+ rewrite /max seq_max_cons.
+ apply/eqP; rewrite eqn_leq; apply/andP; split; last by done.
+ rewrite geq_max; apply/andP; split.
+  by specialize (H 0); simpl in H; rewrite H.
+  rewrite leqn0; apply/eqP; apply: IHxs.
+ intros.
+ specialize (H n.+1).
+ by simpl in *.
+ }
+ rewrite L; first by done.
+ intros.
+ specialize (H n0).
+ by destruct n0; simpl in *; apply/eqP; rewrite leqn0.
+ }
+ { rewrite /max !seq_max_cons.
+ rewrite geq_max; apply/andP; split.
+ + rewrite leq_max; apply/orP; left.
+ by specialize (H 0); simpl in H.
+ + rewrite leq_max; apply/orP; right.
+ apply IHlen.
+ rewrite ltnS in LE2; by done.
+ rewrite ltnS in LE1; by done.
+ intros.
+ specialize (H n1.+1).
+ by simpl in H.
+ }
+ }
+ Qed.
+
+ (* The max element of the distancessequence of a sequence xs is bounded
+ by the last element of xs. Note that all elements of xs are positive.
+ Thus they all lie within the interval [0, last xs]. *)
+ Lemma max_distance_in_seq_le_last_element_of_seq:
+ forall (xs: seq nat),
+ nondecreasing_sequence xs >
+ max (distances xs) <= last xs.
+ Proof.
+ clear.
+ intros.
+ have SIZE: size xs < 2 \/ 2 <= size xs.
+ { destruct (size xs); auto.
+ destruct (n); auto.
+ }
+ move: SIZE => [LT  SIZE2].
+ { destruct xs.
+ rewrite /distances /last /max; simpl; by done.
+ destruct xs; last by done.
+ by unfold max, distances, last; simpl.
+ }
+ apply leq_trans with (last xs  first xs); last by apply leq_subr.
+ have F: forall xs c, (forall x, x \in xs > x <= c) > max xs <= c.
+ { clear; intros.
+ induction xs.
+  by done.
+  rewrite /max seq_max_cons geq_max; apply/andP; split.
+ + by apply H; rewrite in_cons; apply/orP; left.
+ + by apply IHxs; intros; apply H; rewrite in_cons; apply/orP; right.
+ }
+ apply F; clear F.
+ intros.
+ move: H0 => /nthP T; specialize (T 0).
+ move: T => [ind IN DIST].
+ rewrite function_of_distances_is_correct in DIST.
+ rewrite DIST.
+ rewrite leq_sub //.
+ { destruct (xs [ind.+1] == last xs) eqn:EQ.
+  by rewrite leq_eqVlt; apply/orP; left.
+  rewrite /last nth_last. apply H.
+ rewrite (ltn_add2r 1) addn1 size_of_seq_of_distances in IN; last by done.
+ move: IN; rewrite leq_eqVlt; move => /orP [/eqP KKKK].
+ move: EQ; rewrite /last nth_last {1}KK [_.+2.1]pred_Sn; move => /eqP; by done.
+ apply/andP; split; first rewrite (ltn_add2r 1) !addn1 prednK //.
+ + by apply ltn_trans with ind.+2.
+ + by apply ltnW.
+ + by rewrite prednK //; apply ltn_trans with ind.+2.
+ }
+ { destruct (first xs == xs [ind]) eqn:EQ.
+  by rewrite leq_eqVlt; apply/orP; left.
+  rewrite /first nth0. apply H.
+ rewrite (ltn_add2r 1) addn1 size_of_seq_of_distances in IN; last by done.
+ destruct ind; first by move: EQ; rewrite /first nth0; move => /eqP.
+ apply/andP; split; first by done.
+ by apply ltn_trans with ind.+2.
+ }
+ Qed.
+
+ (* Consider two nondecreasing sequences xs and ys and assume that
+ (1) first element of xs is at most the first element of ys and
+ (2) distancessequences of xs is dominated by distancessequence of
+ ys. Then xs is dominated by ys. *)
+ Lemma domination_of_distances_implies_domination_of_seq:
+ forall (xs ys: seq nat),
+ first xs <= first ys >
+ 2 <= size xs >
+ 2 <= size ys >
+ size xs = size ys >
+ nondecreasing_sequence xs >
+ nondecreasing_sequence ys >
+ (forall n, (distances xs)[n] <= (distances ys)[n]) >
+ (forall n, xs[n] <= ys[n]).
+ Proof.
+ clear.
+ intros xs ys.
+ have EX: exists len, size xs <= len /\ size ys <= len.
+ { exists (maxn (size xs) (size ys)).
+ by split; rewrite leq_max; apply/orP; [left  right].
+ }
+ move: EX => [len [LE1 LE2]].
+ generalize dependent xs.
+ generalize dependent ys.
+ induction len.
+ { intros.
+ move: LE1 LE2; rewrite !leqn0 !size_eq0; move => /eqP E1 /eqP E2.
+ by subst.
+ }
+ { intros ? LycSIZE ? LxSIZE FLE Sxs Sys SIZEEQ STRxs STRys LE n.
+ destruct xs as [  x1 xs], ys as [  y1 ys]; try by done.
+ destruct xs as [  x2 xs], ys as [  y2 ys]; try by done.
+ clear Sxs Sys.
+ have F: x2 <= y2.
+ { specialize (STRxs 0 1); simpl in STRxs; feed STRxs; first by done.
+ specialize (STRys 0 1); simpl in STRys; feed STRys; first by done.
+ specialize (LE 0); simpl in LE, FLE.
+ rewrite leqNgt; apply/negP; intros NEQ.
+ move: LE; rewrite leqNgt; move => /negP LE; apply: LE.
+ rewrite (ltn_add2r x1).
+ rewrite subnK //.
+ rewrite subh1 //.
+ rewrite (ltn_add2r y1).
+ rewrite subnK; last first.
+ apply leq_trans with y2; [by done  by rewrite leq_addr].
+ apply leq_ltn_trans with (y2 + y1).
+  by rewrite leq_add2l.
+  by rewrite ltn_add2r.
+ }
+ destruct xs as [  x3 xs], ys as [  y3 ys]; try by done.
+ { destruct n; simpl; first by done.
+ destruct n; simpl; by done.
+ }
+ destruct n; first by simpl in *.
+ simpl; apply IHlen; try done.
+  by simpl in *; apply/eqP; rewrite (eqn_add2r 1) !addn1; apply/eqP.
+  move => m1 m2 /andP [B1 B2].
+ specialize (STRxs m1.+1 m2.+1).
+ feed STRxs.
+ apply/andP; split.
+ + by rewrite ltnS.
+ + by simpl in *; rewrite (ltn_add2r 1) !addn1 in B2.
+ by done.
+  move => m1 m2 /andP [B1 B2].
+ specialize (STRys m1.+1 m2.+1).
+ feed STRys.
+ apply/andP; split.
+ + by rewrite ltnS.
+ + by simpl in *; rewrite (ltn_add2r 1) !addn1 in B2.
+ by done.
+  intros. specialize (LE n0.+1). simpl in LE.
+ unfold distances. simpl. by done.
+ }
+ Qed.
+
+ End Lemmas.
+
+End NondecreasingSequence.
\ No newline at end of file
diff git a/model/schedule/uni/limited/rbf.v b/model/schedule/uni/limited/rbf.v
new file mode 100644
index 0000000000000000000000000000000000000000..bb3c5931b5f1ff219a27c1e971754b2f7dad49ed
 /dev/null
+++ b/model/schedule/uni/limited/rbf.v
@@ 0,0 +1,105 @@
+Require Import rt.util.all.
+Require Import rt.model.time rt.model.arrival.basic.job
+ rt.model.arrival.basic.task_arrival
+ rt.model.priority
+ rt.model.arrival.basic.arrival_sequence.
+Require Import rt.model.schedule.uni.schedule.
+Require Import rt.model.arrival.curves.bounds.
+Require Import rt.analysis.uni.arrival_curves.workload_bound.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq path fintype bigop.
+
+Module RBF.
+
+ Import Job Time ArrivalSequence ArrivalCurves TaskArrival Priority MaxArrivalsWorkloadBound.
+
+ (* In this section, we prove some properties of Request Bound Functions (RBF). *)
+ Section RBFProperties.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent:
+ arrival_times_are_consistent job_arrival arr_seq.
+
+ (* Consider an FP policy that indicates a higherorequal priority relation,
+ and assume that the relation is reflexive and transitive. *)
+ Variable higher_eq_priority: FP_policy Task.
+ Hypothesis H_priority_is_reflexive: FP_is_reflexive higher_eq_priority.
+ Hypothesis H_priority_is_transitive: FP_is_transitive higher_eq_priority.
+
+ (* Let tsk be any task. *)
+ Variable tsk: Task.
+
+ (* Let max_arrivals be a proper arrival curve for task tsk, i.e.,
+ [max_arrival tsk] is (1) an arrival bound of tsk, and (2) it is
+ a monotonic function that equals 0 for the empty interval delta = 0. *)
+ Variable max_arrivals: Task > time > nat.
+ Hypothesis H_proper_arrival_curve:
+ proper_arrival_curve job_task arr_seq max_arrivals tsk.
+
+ (* Let's define some local names for clarity. *)
+ Let task_rbf := task_request_bound_function task_cost max_arrivals tsk.
+
+ (* We prove that [task_rbf 0] is equal to 0. *)
+ Lemma task_rbf_0_zero:
+ task_rbf 0 = 0.
+ Proof.
+ rewrite /task_rbf /task_request_bound_function.
+ apply/eqP; rewrite muln_eq0; apply/orP; right; apply/eqP.
+ by move: H_proper_arrival_curve => [_ [T _]]; apply T.
+ Qed.
+
+ (* We prove that task_rbf is monotone. *)
+ Lemma task_rbf_monotone:
+ monotone task_rbf leq.
+ Proof.
+ rewrite /monotone; intros.
+ rewrite /task_rbf /task_request_bound_function leq_mul2l.
+ apply/orP; right.
+ by move: H_proper_arrival_curve => [_ T]; apply T.
+ Qed.
+
+ (* Consider any job j of tsk. *)
+ Variable j: Job.
+ Hypothesis H_j_arrives: arrives_in arr_seq j.
+ Hypothesis H_job_of_tsk: job_task j = tsk.
+
+ (* Then we prove that task_rbf 1 is greater than or equal to task cost. *)
+ Lemma task_rbf_1_ge_task_cost:
+ task_rbf 1 >= task_cost tsk.
+ Proof.
+ have ALT: forall n, n = 0 \/ n > 0.
+ { by clear; intros n; destruct n; [left  right]. }
+ specialize (ALT (task_cost tsk)); destruct ALT as [Z  POS]; first by rewrite Z.
+ rewrite leqNgt; apply/negP; intros CONTR.
+ move: H_proper_arrival_curve => [ARRB _].
+ specialize (ARRB (job_arrival j) (job_arrival j + 1)).
+ feed ARRB; first by rewrite leq_addr.
+ rewrite addKn in ARRB.
+ move: CONTR; rewrite /task_rbf /task_request_bound_function; move => CONTR.
+ move: CONTR; rewrite {2}[task_cost tsk]muln1 ltn_mul2l; move => /andP [_ CONTR].
+ move: CONTR; rewrite addn1 {3}[1]add0n leq_add2r leqn0; move => /eqP CONTR.
+ move: ARRB; rewrite CONTR leqn0 eqn0Ngt; move => /negP T; apply: T.
+ rewrite /num_arrivals_of_task has_predT.
+ rewrite /arrivals_of_task_between /is_job_of_task.
+ apply/hasP; exists j; last by done.
+ rewrite /jobs_arrived_between addn1 big_nat_recl; last by done.
+ rewrite big_geq ?cats0; last by done.
+ rewrite mem_filter.
+ apply/andP; split.
+  by apply/eqP.
+  move: H_j_arrives => [t ARR].
+ move: (ARR) => CONS.
+ apply H_arrival_times_are_consistent in CONS.
+ by rewrite CONS.
+ Qed.
+
+ End RBFProperties.
+
+End RBF.
\ No newline at end of file
diff git a/model/schedule/uni/limited/schedule.v b/model/schedule/uni/limited/schedule.v
new file mode 100644
index 0000000000000000000000000000000000000000..a8825aa75392bda44468f610f93e37ffe4df0933
 /dev/null
+++ b/model/schedule/uni/limited/schedule.v
@@ 0,0 +1,166 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job.
+Require Import rt.model.schedule.uni.service
+ rt.model.schedule.uni.schedule.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(* In this file, we provide additional definitions and
+ lemmas about lockinserivcecompliant schedules. *)
+ Import Job Epsilon Service UniprocessorSchedule.
+
+ Section Definitions.
+
+ Context {Task: eqType}.
+ Variable task_cost: Task > time.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any uniprocessor schedule. *)
+ Variable sched: schedule Job.
+
+ (* We define the notion of lockin service: lockin service is the amount of service
+ after which a job cannot be preempted until its completion. *)
+ Variable job_lock_in_service: Job > time.
+
+ (* We require the lockin service to be positive for any job, i.e., in order to
+ become nonpreemptive a job must receive at least one unit of service. *)
+ Definition job_lock_in_service_positive :=
+ forall j,
+ arrives_in arr_seq j >
+ job_cost_positive job_cost j >
+ 0 < job_lock_in_service j.
+
+ (* We also require a job's lockin service to be at most the cost of the job. *)
+ Definition job_lock_in_service_le_job_cost :=
+ forall j,
+ arrives_in arr_seq j >
+ job_cost_positive job_cost j >
+ job_lock_in_service j <= job_cost j.
+
+ (* In order to get a consistent schedule, the scheduler should respect the notion of
+ lockin service. We assume that, after a job reaches its lockin service, it
+ cannot be preempted until its completion. *)
+ Definition job_nonpreemptive_after_lock_in_service :=
+ forall j t t',
+ arrives_in arr_seq j >
+ t <= t' >
+ job_lock_in_service j <= service sched j t >
+ ~~ completed_by job_cost sched j t' >
+ scheduled_at sched j t'.
+
+ (* We say that job_lock_in_service is a proper job lockin service iff for all jobs in the
+ arrival sequence the lockin service is (1) positive, (2) no bigger than the costs of
+ the corresponding jobs, and (3) a job becomes nonpreemptive after it reaches the
+ lockin service. *)
+ Definition proper_job_lock_in_service :=
+ job_lock_in_service_positive /\
+ job_lock_in_service_le_job_cost /\
+ job_nonpreemptive_after_lock_in_service.
+
+ (* Similarly, we define the notion of task lockin service: task lockin service is the
+ amount of service after which any job from a task reaches its lockin service. *)
+ Variable task_lock_in_service: Task > time.
+
+ (* A task's lockin service should be at most the cost of the task. *)
+ Definition task_lock_in_service_le_task_cost tsk :=
+ task_lock_in_service tsk <= task_cost tsk.
+
+ (* We say that the lockin service of a task tsk bounds the job lockin service iff for any
+ job j of task tsk the job lockin service is lessthanorequal to the task lockin
+ service. *)
+ Definition task_lock_in_service_bounds_job_lock_in_service tsk :=
+ forall j,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ job_lock_in_service j <= task_lock_in_service tsk.
+
+ (* We say that task_lock_in_service is a proper task lockin service for some task tsk
+ iff [task_lock_in_service tsk] is (1) no bigger than tsk's cost, (2) for any job of
+ task tsk job_lock_in_service is bounded by task_lock_in_service. *)
+ Definition proper_task_lock_in_service tsk :=
+ task_lock_in_service_le_task_cost tsk /\
+ task_lock_in_service_bounds_job_lock_in_service tsk.
+
+ End Definitions.
+
+ Section Examples.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+
+ (* Consider any arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any uniprocessor schedule. *)
+ Variable sched: schedule Job.
+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs_dont_execute:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* In this section we prove that in case of the fully preemptive scheduling model
+ the job_nonpreemptive_after_lock_in_service hypothesis becomes trivial. *)
+ Section FullyPreemptiveModel.
+
+ (* In the fully preemptive model any job can be preempted at any moment. *)
+ Let job_lock_in_service (j: Job) := job_cost j.
+
+ (* Then, we prove that the job_nonpreemptive_after_lock_in_service hypothesis is trivial. *)
+ Lemma job_nonpreemptive_after_lock_in_service_trivial:
+ job_nonpreemptive_after_lock_in_service job_cost arr_seq sched job_lock_in_service .
+ Proof.
+ intros j ? ? ARR LE SERV NCOMP.
+ move: NCOMP => /negP NCOMP; exfalso; apply: NCOMP.
+ move: (H_completed_jobs_dont_execute j t) => SERV2.
+ by apply completion_monotonic with t.
+ Qed.
+
+ End FullyPreemptiveModel.
+
+ (* In this section we prove that in case of the fully nonpreemptive scheduling model
+ the job_nonpreemptive_after_lock_in_service hypothesis holds. *)
+ Section FullyNonPreemptiveModel.
+
+ (* In fully nonpreemptive model any job becomes nonpreemptive as soon as it receives one unit of service. *)
+ Let job_lock_in_service (j: Job) := ε.
+
+ (* Let's import definition of nonpreemptive schedule. *)
+ Require Import rt.model.schedule.uni.nonpreemptive.schedule.
+
+ (* Next, we assume that the schedule is fully nonpreemptive. *)
+ Hypothesis H_is_nonpreemptive_schedule:
+ NonpreemptiveSchedule.is_nonpreemptive_schedule job_cost sched.
+
+ (* Then, we prove that the job_nonpreemptive_after_lock_in_service hypothesis holds. *)
+ Lemma property_last_segment_is_nonpreemptive_holds:
+ job_nonpreemptive_after_lock_in_service job_cost arr_seq sched job_lock_in_service .
+ Proof.
+ unfold NonpreemptiveSchedule.is_nonpreemptive_schedule in *.
+ intros j ? ? ARR LE NEQ NCOMPL; unfold job_lock_in_service in *.
+ have POS: 0 < job_cost j.
+ { rewrite [0 < _]Bool.negb_involutive eqn0Ngt; apply/negP; intros ZERO.
+ move: ZERO => /eqP ZERO.
+ rewrite /completed_by in NCOMPL.
+ rewrite ZERO lt0n in NCOMPL.
+ move: (H_completed_jobs_dont_execute j t') => NN.
+ by rewrite ZERO leqNgt in NN; move: NN => /negP NN; apply: NN.
+ }
+ move: NEQ => /sum_seq_gt0P [ts [IN SCHED]].
+ rewrite lt0b in SCHED.
+ apply H_is_nonpreemptive_schedule with ts; try done.
+ apply ltnW, leq_trans with t; last by done.
+ by rewrite mem_iota add0n subn0 in IN; move: IN => /andP [_ IN].
+ Qed.
+
+ End FullyNonPreemptiveModel.
+
+ End Examples.
+
diff git a/model/schedule/uni/nonpreemptive/platform.v b/model/schedule/uni/nonpreemptive/platform.v
new file mode 100644
index 0000000000000000000000000000000000000000..45b8a76f6230a758ccf1433df52f9951e40a9be9
 /dev/null
+++ b/model/schedule/uni/nonpreemptive/platform.v
@@ 0,0 +1,121 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.task rt.model.arrival.basic.job rt.model.priority rt.model.arrival.basic.task_arrival.
+Require Import rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.basic.platform.
+Require Import rt.model.schedule.uni.nonpreemptive.schedule.
+From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
+
+Module NonpreemptivePlatform.
+
+ Import Job SporadicTaskset UniprocessorSchedule Priority.
+
+ (* In this section, we define properties of the processor platform. *)
+ Section Properties.
+
+ Context {sporadic_task: eqType}.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > sporadic_task.
+
+ (* Consider any job arrival sequence ...*)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any uniprocessor schedule of these jobs. *)
+ Variable sched: schedule Job.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_scheduled_at := scheduled_at sched.
+
+ (* First, we define the notion of a preemption point. *)
+ Section PreemptionPoint.
+
+ (* We say that t is a preemption point iff (a) t is equal to 0
+ or (b) there is no scheduling job at time t or
+ (c) a job that was scheduled at time (t  1) and
+ has completed by t exists. *)
+ Definition is_preemption_point' (t: time) :=
+ t = 0
+ \/ sched (t1) = None
+ \/ exists j, scheduled_at sched j (t  1) /\ job_completed_by j t.
+
+ (* Moreover, we provide a shorter definition, more convenient for the proofs. *)
+ Definition is_preemption_point (t: time) :=
+ t = 0 \/ forall j, job_scheduled_at j (t  1) > job_completed_by j t.
+
+ (* Let's prove that the definitions above are equal. *)
+ Lemma defitions_of_preemption_point_are_equal:
+ forall t, is_preemption_point t <> is_preemption_point' t.
+ Proof.
+ unfold is_preemption_point, is_preemption_point'.
+ intros; split; intros.
+ {
+ destruct H as [H  H]; [by left  right].
+ destruct (sched (t1)) eqn:SCHED; [right; exists s  by left].
+ move: SCHED => /eqP SCHED.
+ by split; last by apply H in SCHED.
+ }
+ {
+ destruct H as [H  [H  H]]; [by left  ]; right; intros.
+ unfold job_scheduled_at, scheduled_at in H0. rewrite H in H0. inversion H0.
+ inversion H as [j' [H1 H2]]. unfold job_scheduled_at in H0.
+ have EQ: j = j'. by apply (only_one_job_scheduled sched) with (t := t1).
+ by subst j'.
+ }
+ Qed.
+
+ End PreemptionPoint.
+
+ (* Next, we define properties related to execution. *)
+ Section Execution.
+
+ (* We say that a scheduler is workconserving iff whenever a job j
+ is backlogged, the processor is always busy with another job. *)
+ (* Imported from the preemptive schedule. *)
+ Definition work_conserving := Platform.work_conserving job_cost.
+
+ End Execution.
+
+ (* Next, we define properties related to FP scheduling. *)
+ Section FP.
+
+ (* We say that an FP policy...*)
+ Variable higher_eq_priority: FP_policy sporadic_task.
+
+ (* ...is respected by the schedule iff a scheduled task has
+ higher (or same) priority than (as) any backlogged task at
+ every preemption point. *)
+ Definition respects_FP_policy_at_preemption_point :=
+ forall j j_hp t,
+ arrives_in arr_seq j >
+ backlogged job_arrival job_cost sched j t >
+ scheduled_at sched j_hp t >
+ is_preemption_point t >
+ higher_eq_priority (job_task j_hp) (job_task j).
+
+ End FP.
+
+ (* Next, we define properties related to JLFP policies. *)
+ Section JLFP.
+
+ (* We say that a JLFP policy ...*)
+ Variable higher_eq_priority: JLFP_policy Job.
+
+ (* ... is respected by the scheduler iff a scheduled job has
+ higher (or same) priority than (as) any backlogged job at
+ every preemption point. *)
+ Definition respects_JLFP_policy_at_preemption_point :=
+ forall j j_hp t,
+ arrives_in arr_seq j >
+ backlogged job_arrival job_cost sched j t >
+ scheduled_at sched j_hp t >
+ is_preemption_point t >
+ higher_eq_priority j_hp j.
+
+ End JLFP.
+
+ End Properties.
+
+End NonpreemptivePlatform.
\ No newline at end of file
diff git a/model/schedule/uni/nonpreemptive/schedule.v b/model/schedule/uni/nonpreemptive/schedule.v
new file mode 100644
index 0000000000000000000000000000000000000000..3048327daf6083ea80963afb581980e1fb11809e
 /dev/null
+++ b/model/schedule/uni/nonpreemptive/schedule.v
@@ 0,0 +1,355 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.job.
+Require Import rt.model.schedule.uni.schedule.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+Module NonpreemptiveSchedule.
+
+ Export UniprocessorSchedule.
+
+ Section Definitions.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+
+ (* Consider any uniprocessor schedule. *)
+ Variable sched: schedule Job.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_completed_by := completed_by job_cost sched.
+ Let job_remaining_cost j t := remaining_cost job_cost sched j t.
+
+ (* We define schedule to be nonpreemptive iff every job remains scheduled until completion. *)
+ Definition is_nonpreemptive_schedule :=
+ forall j t t',
+ t <= t' >
+ scheduled_at sched j t >
+ ~~ job_completed_by j t' >
+ scheduled_at sched j t'.
+
+ (* In this section, we prove some basic lemmas about nonpreemptive schedules. *)
+ Section Lemmas.
+
+ (* Assume that we have a nonpreemptive schedule. *)
+ Hypothesis H_nonpreemptive: is_nonpreemptive_schedule.
+
+ Section BasicLemmas.
+
+ (* Consider any job j. *)
+ Variable j: Job.
+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs_dont_execute:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* First, we show that if j is scheduled at any two time instants,
+ then it is also scheduled at any time between them. *)
+ Lemma continuity_of_nonpreemptive_scheduling:
+ forall t t1 t2,
+ t1 <= t <= t2 >
+ scheduled_at sched j t1 >
+ scheduled_at sched j t2 >
+ scheduled_at sched j t.
+ Proof.
+ move => t t1 t2 /andP [GT LE] SCHEDt1 SCHEDt2.
+ unfold is_nonpreemptive_schedule, job_completed_by in *.
+ apply H_nonpreemptive with (t := t1); [by done by done ].
+ apply /negP; intros COMP.
+ apply (scheduled_implies_not_completed job_cost) in SCHEDt2; last by done.
+ apply completion_monotonic with (t' := t2) in COMP; last by done.
+ by move: SCHEDt2 => /negP SCHEDt2; apply: SCHEDt2.
+ Qed.
+
+ (* Next, we show that in any nonpreemptive schedule, once a job is scheduled,
+ it cannot be preempted until completion. *)
+ Lemma in_nonpreemption_schedule_preemption_implies_completeness:
+ forall t t' ,
+ t <= t' >
+ scheduled_at sched j t >
+ ~~ scheduled_at sched j t' >
+ job_completed_by j t'.
+ Proof.
+ intros t t' LE SCHED; apply contraNT.
+ by apply H_nonpreemptive with (t := t).
+ Qed.
+
+ End BasicLemmas.
+
+ (* In this section, we prove properties related to job completion. *)
+ Section CompletionUnderNonpreemptive.
+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs_dont_execute:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* If job j is scheduled at time t, then it must complete by (t + remaining_cost j t). *)
+ Lemma job_completes_after_remaining_cost:
+ forall j t,
+ scheduled_at sched j t >
+ job_completed_by j (t + job_remaining_cost j t).
+ Proof.
+ intros j t SCHED.
+ rewrite /job_completed_by /completed_by.
+ rewrite /service /service_during.
+ rewrite (@big_cat_nat _ _ _ t) //= ?leq_addr //.
+ apply leq_trans with (n := service sched j t + job_remaining_cost j t);
+ first by rewrite /remaining_cost subnKC //.
+ rewrite leq_add2l.
+ set t2 := t + _.
+ apply leq_trans with (n := \sum_(t <= i < t2) 1);
+ first by simpl_sum_const; rewrite /t2 addKn.
+ apply leq_sum_nat.
+ move => i /andP [GE LT _].
+ rewrite lt0n eqb0 negbK.
+ apply (H_nonpreemptive j t i); try (by done).
+ unfold t2 in *; clear t2.
+ have NOTCOMP: ~~ job_completed_by j t.
+ {
+ apply contraT. rewrite negbK. intros COMP.
+ apply completed_implies_not_scheduled in COMP; last by done.
+ by rewrite SCHED in COMP.
+ }
+ apply job_doesnt_complete_before_remaining_cost in NOTCOMP; last by done.
+ apply contraT; rewrite negbK; intros COMP.
+ exfalso; move: NOTCOMP => /negP NOTCOMP; apply: NOTCOMP.
+ apply completion_monotonic with (t0 := i); try ( by done).
+ by apply subh3; first rewrite addn1.
+ Qed.
+
+ End CompletionUnderNonpreemptive.
+
+ (* In this section, we determine bounds on the length of the execution interval. *)
+ Section ExecutionInterval.
+
+ (* Assume that jobs do not execute after completion. *)
+ Hypothesis H_completed_jobs_dont_execute:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* Let j be any job scheduled at time t. *)
+ Variable j: Job.
+ Variable t: time.
+ Hypothesis H_j_is_scheduled_at_t: scheduled_at sched j t.
+
+ (* Is this section we show that there is a bound for how early job j can start. *)
+ Section LeftBound.
+
+ (* We prove that job j is scheduled at time (t  service sched j t)... *)
+ Lemma j_is_scheduled_at_t_minus_service:
+ scheduled_at sched j (t  service sched j t).
+ Proof.
+ unfold is_nonpreemptive_schedule in *.
+ apply contraT; intros CONTRA; exfalso.
+ rename H_j_is_scheduled_at_t into SCHED.
+ have COSTPOS: job_cost j > 0.
+ { apply (scheduled_implies_not_completed job_cost) in SCHED; last by done.
+ unfold job_completed_by, completed_by in SCHED.
+ apply contraT; rewrite eqn0Ngt.
+ move => /eqP EQ0.
+ rewrite EQ0 in SCHED.
+ by rewrite ltnNge ltn0 in SCHED.
+ }
+
+ have H: service sched j (t + job_remaining_cost j t) == job_cost j.
+ { rewrite eqn_leq; apply/andP; split; eauto 2.
+ by apply job_completes_after_remaining_cost.
+ }
+ unfold job_completed_by, completed_by in H.
+ move: H => /eqP H.
+ unfold service, service_during in H.
+ rewrite (@big_cat_nat _ _ _ (t  service sched j t)) //= in H;
+ last by rewrite leq_subLR addnC addnA leq_addr.
+ have R: forall a b c, a + b = c > b < c > a > 0.
+ { by intros a b c EQ LT; induction a;
+ first by rewrite add0n in EQ; subst b;
+ rewrite ltnn in LT.
+ }
+ apply R in H; last first.
+ {
+ have CUMLED := cumulative_service_le_delta sched j 0 t.
+ have CUMLEJC := cumulative_service_le_job_cost _ _ j H_completed_jobs_dont_execute 0 t.
+ rewrite (@big_cat_nat _ _ _ ((t  service sched j t).+1)) //=.
+ {
+ rewrite big_nat_recl; last by done.
+ rewrite big_geq; last by done.
+ rewrite eqb0 in CONTRA; move: CONTRA => /eqP CONTRA.
+ rewrite /service_at CONTRA add0n add0n.
+ apply leq_ltn_trans with
+ (t + job_remaining_cost j t  ((t  service sched j t).+1)).
+ set (t  service sched j t).+1 as T.
+ apply leq_trans with (\sum_(T <= i < t + job_remaining_cost j t) 1).
+ rewrite leq_sum //; intros; by destruct (scheduled_at sched j i).
+ simpl_sum_const. by done.
+ unfold job_remaining_cost, remaining_cost.
+ rewrite addn1 addn1 subh1; first by
+ by rewrite leq_subLR addnBA;
+ first by rewrite addnA [1+job_cost j]addnC addnA subh1.
+ {
+ rewrite subh1; last by done.
+ rewrite leq_subLR addnA.
+ rewrite addnBA; last by done.
+ rewrite [_+t]addnC [_+job_cost j]addnC addnA.
+ rewrite addnBA; last by done.
+ by rewrite subnn addn0 addnC leq_add2r.
+ }
+ }
+ {
+ unfold remaining_cost.
+ rewrite addnBA; last by done.
+ rewrite addn1 subh1; last by done.
+ rewrite leq_subLR addnBA; last by done.
+ rewrite addnA [_+t]addnC addnA leq_add2l addnBA; last by done.
+ by rewrite addnC addnBA; first by rewrite subnn addn0.
+ }
+ }
+ {
+ rewrite lt0n in H; move: H => /neqP H; apply: H.
+ rewrite big_nat_cond big1 //; move => i /andP [/andP [_ LT] _].
+ apply /eqP; rewrite eqb0; apply /negP; intros CONT.
+
+ have Y := continuity_of_nonpreemptive_scheduling j _ (t  service sched j t) i t.
+ feed_n 4 Y; try(done).
+ by apply/andP; split; [rewrite ltnW  rewrite leq_subr].
+ by move: CONTRA => /negP CONTRA; apply CONTRA.
+ }
+ Qed.
+
+ (* ... and it is not scheduled at time (t  service sched j t  1). *)
+ Lemma j_is_not_scheduled_at_t_minus_service_minus_one:
+ t  service sched j t > 0 >
+ ~~ scheduled_at sched j (t  service sched j t  1).
+ Proof.
+ rename H_j_is_scheduled_at_t into SCHED.
+ intros GT; apply/negP; intros CONTRA.
+ have L1 := job_doesnt_complete_before_remaining_cost
+ job_cost sched j H_completed_jobs_dont_execute t.
+ feed L1; first by rewrite scheduled_implies_not_completed.
+ have L2 := job_completes_after_remaining_cost
+ H_completed_jobs_dont_execute
+ j (tservice sched j t  1).
+ feed L2; first by done.
+ have EQ:
+ t + job_remaining_cost j t  1 =
+ t  service sched j t  1 + job_remaining_cost j (t  service sched j t  1).
+ {
+ have T1: service sched j (t  service sched j t  1) = 0.
+ {
+
+ rewrite [service _ _ _]/service /service_during.
+ rewrite big_nat_cond big1 //; move => t' /andP [/andP [_ LT] _].
+ apply /eqP; rewrite eqb0; apply /negP; intros CONTR.
+
+ have COMPL: completed_by job_cost sched j (t + job_remaining_cost j t  1).
+ {
+ apply completion_monotonic with (t0 := t' + job_remaining_cost j t');
+ [ by apply job_completes_after_remaining_cost].
+ unfold remaining_cost.
+ have LLF: t' < t  service sched j t.
+ {
+ by apply ltn_trans with (t  service sched j t  1);
+ last by rewrite addn1 subh1 // addnBA // subnn addn0.
+ } clear LT.
+ rewrite !addnBA;
+ try(rewrite H_completed_jobs_dont_execute //).
+ rewrite [t' + _]addnC [t + _]addnC.
+ rewrite addnBA; last by rewrite cumulative_service_le_delta.
+ rewrite addnBA; last by rewrite cumulative_service_le_delta.
+ rewrite addnBA ?leq_add2l; last by done.
+ by apply leq_trans with (t' + 1  1);
+ rewrite addn1 subn1 pred_Sn;
+ [rewrite leq_subr  rewrite subh3 // addn1].
+ }
+ have L3 := job_doesnt_complete_before_remaining_cost job_cost sched
+ j H_completed_jobs_dont_execute t;
+ feed L3; first by rewrite scheduled_implies_not_completed.
+ unfold job_completed_by in *.
+ by move: L3 => /negP L3; apply L3.
+ }
+ rewrite /job_remaining_cost /remaining_cost T1 subn0 addnBA; last by done.
+ rewrite subh1.
+ by rewrite [(tservice sched j t) + _  _]subh1.
+ by rewrite cumulative_service_le_delta.
+ }
+ move: L1 => /neqP L1; apply: L1.
+ rewrite EQ in L2.
+ by unfold job_completed_by, completed_by in L2; move: L2 => /eqP L2.
+ Qed.
+
+ (* Using the previous lemma, we show that job j cannot be scheduled
+ before (t  service sched j t). *)
+ Lemma j_is_not_scheduled_earlier_t_minus_service:
+ forall t',
+ t' < t  service sched j t >
+ ~~ scheduled_at sched j t'.
+ Proof.
+ intros t' GT.
+ have NOTSCHED := j_is_not_scheduled_at_t_minus_service_minus_one;
+ feed NOTSCHED; first by apply leq_ltn_trans with t'.
+ apply/negP; intros CONTRA.
+ move: NOTSCHED => /negP NOTSCHED; apply: NOTSCHED.
+ apply continuity_of_nonpreemptive_scheduling with (t1 := t') (t2 := t);
+ [ by done   by done  by done ].
+ apply/andP; split; last by apply leq_trans with (t  service sched j t); rewrite leq_subr.
+ rewrite [t']pred_Sn subn1 leq_sub2r //.
+ Qed.
+
+ End LeftBound.
+
+ (* Is this section we prove that job j cannot be scheduled after (t + remaining_cost j t  1). *)
+ Section RightBound.
+
+ (* We show that if job j is scheduled at time t,
+ then it is also scheduled at time (t + remaining_cost j t  1)... *)
+ Lemma j_is_scheduled_at_t_plus_remaining_cost_minus_one:
+ scheduled_at sched j (t + job_remaining_cost j t  1).
+ Proof.
+ move: (H_j_is_scheduled_at_t) => COMP.
+ apply (scheduled_implies_not_completed job_cost) in COMP; last by done.
+ apply job_doesnt_complete_before_remaining_cost in COMP; last by done.
+ move: COMP; apply contraR; intros CONTR.
+ apply in_nonpreemption_schedule_preemption_implies_completeness
+ with (t:=t); [by done by done].
+ rewrite subh3 // ?leq_add2l.
+ by rewrite scheduled_implies_positive_remaining_cost //.
+ Qed.
+
+ (* ... and it is not scheduled after (t + remaining cost j t  1). *)
+ Lemma j_is_not_scheduled_after_t_plus_remaining_cost_minus_one:
+ forall t',
+ t + job_remaining_cost j t <= t' >
+ ~~ scheduled_at sched j t'.
+ Proof.
+ intros t' GE.
+ unfold job_completed_by in *.
+ rename H_j_is_scheduled_at_t into SCHED.
+ apply job_completes_after_remaining_cost in SCHED; last by done.
+ by apply (completion_monotonic job_cost) with (t' := t') in SCHED; first
+ by apply (completed_implies_not_scheduled job_cost).
+ Qed.
+
+ End RightBound.
+
+ (* To conclude, we identify the interval where job j is scheduled. *)
+ Lemma nonpreemptive_executing_interval:
+ forall t',
+ t  service sched j t <= t' < t + job_remaining_cost j t >
+ scheduled_at sched j t'.
+ Proof.
+ move => t' /andP [GE LE].
+ move: (H_j_is_scheduled_at_t) => SCHED1; move: (H_j_is_scheduled_at_t) => SCHED2.
+ rewrite addn1 in LE; apply subh3 with (m := t') (p := 1) in LE;
+ apply continuity_of_nonpreemptive_scheduling with
+ (t1 := t  service sched j t)
+ (t2 := t + job_remaining_cost j t  1); first by done.
+  by apply/andP;split.
+  by apply j_is_scheduled_at_t_minus_service.
+  by apply j_is_scheduled_at_t_plus_remaining_cost_minus_one.
+ Qed.
+
+ End ExecutionInterval.
+
+ End Lemmas.
+
+ End Definitions.
+
+End NonpreemptiveSchedule.
\ No newline at end of file
diff git a/model/schedule/uni/response_time.v b/model/schedule/uni/response_time.v
index 4e18a8a92844016eaf2524bcef52d5452e5e1358..1d46b877fa45437f2b7fffce339a9d20684c5b85 100644
 a/model/schedule/uni/response_time.v
+++ b/model/schedule/uni/response_time.v
@@ 100,15 +100,11 @@ Module ResponseTime.
H_completed_jobs_dont_execute into EXEC; ins.
unfold is_response_time_bound_of_task, completed_by,
completed_jobs_dont_execute in *.
 apply/eqP; rewrite leqn0.
 rewrite < leq_add2l with (p := job_cost j).
 move: RT => /eqP RT; rewrite {1}RT addn0.
 apply leq_trans with (n := service sched j t'.+1);
 last by apply EXEC.
 unfold service, service_during.
 rewrite > big_cat_nat with (p := t'.+1) (n := job_arrival j + R);
 [rewrite leq_add2l /=  by ins  by apply ltnW].
 by rewrite big_nat_recr // /=; apply leq_addl.
+ apply/eqP; rewrite eqb0; apply/negP; intros CONTR.
+ unfold response_time_bounded_by,is_response_time_bound_of_job in *.
+ eapply completion_monotonic in RT; eauto 2.
+ apply completed_implies_not_scheduled in RT; eauto 2.
+ by move: RT => /negP RT; apply:RT.
Qed.
(* The same applies for the cumulative service of job j. *)
diff git a/model/schedule/uni/schedulability.v b/model/schedule/uni/schedulability.v
index 27d34ca0044693da7d34d313735c3c1126786ec3..bb187359784d33e96055e160c6c6f9cba99d4b3d 100644
 a/model/schedule/uni/schedulability.v
+++ b/model/schedule/uni/schedulability.v
@@ 108,10 +108,10 @@ Module Schedulability.
unfold valid_sporadic_job, valid_realtime_job in *.
intros j ARRj JOBtsk.
apply completion_monotonic with (t := job_arrival j + R);
 [by done   by apply H_response_time_bounded].
+ last by apply H_response_time_bounded.
rewrite leq_add2l.
apply: (leq_trans H_R_le_deadline).
 by rewrite H_job_deadline_eq_task_deadline // JOBtsk leqnn.
+ by rewrite H_job_deadline_eq_task_deadline // JOBtsk leqnn.
Qed.
End ResponseTimeIsBounded.
diff git a/model/schedule/uni/schedule.v b/model/schedule/uni/schedule.v
index d0dd40c32c740bd8b64f405e933dbf150ca5bd80..f7af531b5751eef093ae6473fa2ae07731040553 100644
 a/model/schedule/uni/schedule.v
+++ b/model/schedule/uni/schedule.v
@@ 8,7 +8,7 @@ Module UniprocessorSchedule.
Export Time ArrivalSequence.
Section Schedule.

+
(* We begin by defining a uniprocessor schedule. *)
Section ScheduleDef.
@@ 55,14 +55,19 @@ Module UniprocessorSchedule.
(* Next, we say that job j has completed by time t if it received enough
service in the interval [0, t). *)
 Definition completed_by (t: time) := service t == job_cost j.
+ Definition completed_by (t: time) := job_cost j <= service t.
(* Job j is pending at time t iff it has arrived but has not yet completed. *)
Definition pending (t: time) := has_arrived job_arrival j t && ~~ completed_by t.
+ (* Job j is pending earlier and at time t iff it has arrived before time t
+ and has not been completed yet. *)
+ Definition pending_earlier_and_at (t: time) :=
+ arrived_before job_arrival j t && ~~ completed_by t.
+
(* Job j is backlogged at time t iff it is pending and not scheduled. *)
Definition backlogged (t: time) := pending t && ~~ scheduled_at t.

+
End JobProperties.
(* In this section, we define some properties of the processor. *)
@@ 80,6 +85,44 @@ Module UniprocessorSchedule.
Definition total_service (t2: time) := total_service_during 0 t2.
End ProcessorProperties.
+
+ Section PropertyOfSequentiality.
+
+ Context {Task: eqType}.
+ Variable job_task: Job > Task.
+
+ (* We say that two jobs j1 and j2 are from the same task, if job_task j1 is equal to job_task j2. *)
+ Let same_task j1 j2 := job_task j1 == job_task j2.
+
+ (* We say that the jobs are sequential if they are executed in the order they arrived. *)
+ Definition sequential_jobs :=
+ forall j1 j2 t,
+ same_task j1 j2 >
+ job_arrival j1 < job_arrival j2 >
+ scheduled_at j2 t >
+ completed_by j1 t.
+
+ (* Assume the hypothesis about sequential jobs holds. *)
+ Hypothesis H_sequential_jobs: sequential_jobs.
+
+ (* A simple corollary of this hypothesis is that the scheduler
+ executes a job with the earliest arrival time. *)
+ Corollary scheduler_executes_job_with_earliest_arrival:
+ forall j1 j2 t,
+ same_task j1 j2 >
+ ~~ completed_by j2 t >
+ scheduled_at j1 t >
+ job_arrival j1 <= job_arrival j2.
+ Proof.
+ intros ? ? t TSK NCOMPL SCHED.
+ rewrite /same_task eq_sym in TSK.
+ have SEQ := H_sequential_jobs j2 j1 t TSK.
+ rewrite leqNgt; apply/negP; intros ARR.
+ move: NCOMPL => /negP NCOMPL; apply: NCOMPL.
+ by apply SEQ.
+ Qed.
+
+ End PropertyOfSequentiality.
End ScheduleProperties.
@@ 117,6 +160,11 @@ Module UniprocessorSchedule.
(* Consider any uniprocessor schedule. *)
Variable sched: schedule Job.
+ (* Let's define the remaining cost of job j as the amount of service
+ that has to be received for its completion. *)
+ Definition remaining_cost j t :=
+ job_cost j  service sched j t.
+
(* Let's begin with lemmas about service. *)
Section Service.
@@ 141,15 +189,29 @@ Module UniprocessorSchedule.
last by simpl_sum_const; rewrite addKn leqnn.
by apply leq_sum; intros t0 _; apply leq_b1.
Qed.

+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs:
+ completed_jobs_dont_execute job_cost sched.
+
+ (* Note that if a job scheduled at some time t then remaining
+ cost at this point is positive *)
+ Lemma scheduled_implies_positive_remaining_cost:
+ forall t,
+ scheduled_at sched j t >
+ remaining_cost j t > 0.
+ Proof.
+ intros.
+ rewrite subn_gt0 /service /service_during.
+ apply leq_trans with (\sum_(0 <= t0 < t.+1) service_at sched j t0);
+ last by rewrite H_completed_jobs.
+ by rewrite big_nat_recr //= addn1 leq_add2l lt0b.
+ Qed.
+
End Service.
(* Next, we prove properties related to job completion. *)
Section Completion.

 (* Assume that completed jobs do not execute. *)
 Hypothesis H_completed_jobs:
 completed_jobs_dont_execute job_cost sched.
(* Let j be any job that is to be scheduled. *)
Variable j: Job.
@@ 160,13 +222,16 @@ Module UniprocessorSchedule.
t <= t' >
completed_by job_cost sched j t >
completed_by job_cost sched j t'.
 Proof.
 unfold completed_by; move => t t' LE /eqP COMPt.
 rewrite eqn_leq; apply/andP; split; first by apply H_completed_jobs.
 by apply leq_trans with (n := service sched j t);
 [by rewrite COMPt  by apply extend_sum].
 Qed.
+ Proof.
+ unfold completed_by; move => t t' LE COMPt.
+ apply leq_trans with (service sched j t); first by done.
+ by rewrite /service /service_during [in X in _ <= X](@big_cat_nat _ _ _ t) //= leq_addr.
+ Qed.
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs:
+ completed_jobs_dont_execute job_cost sched.
+
(* We also prove that a completed job cannot be scheduled. *)
Lemma completed_implies_not_scheduled :
forall t,
@@ 178,10 +243,22 @@ Module UniprocessorSchedule.
intros t COMPLETED.
apply/negP; red; intro SCHED.
have BUG := COMP j t.+1.
 rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
+ rewrite leqNgt in BUG; move: BUG => /negP BUG; apply: BUG.
unfold service, service_during; rewrite big_nat_recr // /= addn1.
 apply leq_add; first by move: COMPLETED => /eqP <.
 by rewrite /service_at SCHED.
+ apply leq_add; first by done.
+ by rewrite /service_at SCHED.
+ Qed.
+
+ (* ... and that a scheduled job cannot be completed. *)
+ Lemma scheduled_implies_not_completed:
+ forall t,
+ scheduled_at sched j t >
+ ~~ completed_by job_cost sched j t.
+ Proof.
+ move => t SCHED.
+ rewrite /completed_by; apply/negP; intros CONTR.
+ apply completed_implies_not_scheduled in CONTR.
+ by move: CONTR => /negP CONTR; apply: CONTR.
Qed.
(* Next, we show that the service received by job j in any interval
@@ 199,7 +276,94 @@ Module UniprocessorSchedule.
rewrite > big_cat_nat with (m := 0) (n := t);
[by apply leq_addl  by ins  by rewrite leqNgt negbT //].
Qed.

+
+ (* If a job isn't complete at time t,
+ it can't be completed at time (t + remaining_cost j t  1). *)
+ Lemma job_doesnt_complete_before_remaining_cost:
+ forall t,
+ ~~ completed_by job_cost sched j t >
+ ~~ completed_by job_cost sched j (t + remaining_cost j t  1).
+ Proof.
+ intros t GT0.
+ unfold remaining_cost, completed_by in *.
+ have COSTGT0: job_cost j > 0.
+ { apply contraT; rewrite eqn0Ngt.
+ move => /eqP EQ0.
+ by rewrite EQ0 ltnNge ltn0 in GT0.
+ }
+ rewrite ltnNge.
+ rewrite /service /service_during.
+ set delta := (X in (t + X  1)).
+ have NONZERO: delta > 0.
+ { rewrite ltnNge in GT0.
+ by rewrite /delta subn_gt0.
+ }
+ rewrite (@big_cat_nat _ _ _ t) //= ?leq_addr //;
+ last by rewrite addnBA; [rewrite leq_addr  done].
+ apply leq_ltn_trans with (n := service sched j t + \sum_(t <= i < t + delta  1) 1);
+ first by rewrite leq_add2l; apply leq_sum; intros; apply leq_b1.
+ simpl_sum_const.
+ rewrite addnBA // addKn.
+ rewrite addnBA // /delta.
+ rewrite subnKC; last by done.
+ rewrite subn1 (ltn_add2r 1) addn1.
+ by rewrite prednK // addn1 ltnSn.
+ Qed.
+
+ (* In this section, we prove that the job with a positive
+ cost must be scheduled to be completed. *)
+ Section JobMustBeScheduled.
+
+ (* We assume that job j has positive cost, from which we can
+ infer that there always is a time in which j is pending. *)
+ Hypothesis H_positive_cost: job_cost j > 0.
+
+ (* Assume that jobs must arrive to execute. *)
+ Hypothesis H_jobs_must_arrive:
+ jobs_must_arrive_to_execute job_arrival sched.
+
+ (* Then, we prove that the job with a positive cost
+ must be scheduled to be completed. *)
+ Lemma completed_implies_scheduled_before:
+ forall t,
+ completed_by job_cost sched j t >
+ exists t',
+ job_arrival j <= t' < t
+ /\ scheduled_at sched j t'.
+ Proof.
+ intros t COMPL.
+ induction t.
+ { exfalso.
+ unfold completed_by, service, service_during in COMPL.
+ move: COMPL; rewrite big_geq //; move => /eqP H0.
+ by destruct (job_cost j).
+ }
+ destruct (completed_by job_cost sched j t) eqn:COMPLatt.
+ { feed IHt; first by done.
+ move: IHt => [t' [JA SCHED]].
+ exists t'. split; first apply/andP; first split.
+  by apply H_jobs_must_arrive in SCHED.
+  move: JA => /andP [_ LT]. by apply leq_trans with t.
+  by done.
+ }
+ { apply negbT in COMPLatt.
+ unfold completed_by in *.
+ rewrite ltnNge in COMPLatt.
+ unfold service, service_during in COMPL.
+ rewrite big_nat_recr //= in COMPL.
+ have SCHED: scheduled_at sched j t.
+ { rewrite {2}/service_at in COMPL.
+ destruct (scheduled_at sched j t); first by done.
+ rewrite addn0 in COMPL.
+ by exfalso; move: COMPL; rewrite leqNgt; move => /negP C; apply: C.
+ }
+ exists t. split; first apply/andP; first split; try done.
+ by apply H_jobs_must_arrive in SCHED.
+ }
+ Qed.
+
+ End JobMustBeScheduled.
+
End Completion.
(* In this section we prove properties related to job arrivals. *)
@@ 272,7 +436,7 @@ Module UniprocessorSchedule.
(* Let j be any job. *)
Variable j: Job.
 (* First, we show that if job j is scheduled, then it must be pending. *)
+ (* We show that if job j is scheduled, then it must be pending. *)
Lemma scheduled_implies_pending:
forall t,
scheduled_at sched j t >
@@ 287,9 +451,24 @@ Module UniprocessorSchedule.
have BUG := COMP j t.+1.
rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
unfold service, service_during; rewrite addn1 big_nat_recr // /=.
 apply leq_add;
 first by move: COMPLETED => /eqP COMPLETED; rewrite COMPLETED.
 by rewrite /service_at SCHED.
+ apply leq_add; first by done.
+ by rewrite /service_at SCHED.
+ Qed.
+
+ (* Consider any arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* Then we prove that the job is pending at the moment of its arrival. *)
+ Lemma job_pending_at_arrival:
+ arrives_in arr_seq j >
+ job_cost j > 0 >
+ pending job_arrival job_cost sched j (job_arrival j).
+ Proof.
+ intros ARR POS.
+ apply/andP; split; first by rewrite /has_arrived.
+ rewrite ltnNge.
+ rewrite /service /service_during (ignore_service_before_arrival); try done.
+ by rewrite big_geq; eauto 2.
Qed.
End Pending.
@@ 461,5 +640,5 @@ Module UniprocessorSchedule.
End Lemmas.
End Schedule.

+
End UniprocessorSchedule.
\ No newline at end of file
diff git a/model/schedule/uni/service.v b/model/schedule/uni/service.v
index cf537c960a28cab5d6387427858ca9e1a587dcd8..e85763d78c392451df988c9d5fe4a281cf5d09f5 100644
 a/model/schedule/uni/service.v
+++ b/model/schedule/uni/service.v
@@ 148,9 +148,344 @@ Module Service.
Qed.
End ServiceBoundedByIntervalLength.

+
End Lemmas.

+
End ServiceOverSets.
+ (* In this section, we introduce some auxiliary definitions about the service. *)
+ Section ExtraDefinitions.
+
+ Context {Task: eqType}.
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any uniprocessor schedule of these jobs. *)
+ Variable sched: schedule Job.
+
+ (* Let tsk be the task to be analyzed. *)
+ Variable tsk: Task.
+
+ (* Recall the notion of a job of task tsk. *)
+ Let of_task_tsk j := job_task j == tsk.
+
+ (* We define the cumulative task service received by the jobs from the task
+ that arrives in interval [ta1, ta2) within time interval [t1, t2). *)
+ Definition task_service_of_jobs_received_in ta1 ta2 t1 t2 :=
+ service_of_jobs sched (jobs_arrived_between arr_seq ta1 ta2) of_task_tsk t1 t2.
+
+ (* For simplicity, let's define a shorter version of task service
+ for jobs that arrive and execute in the same interval [t1, t2). *)
+ Definition task_service_between t1 t2 := task_service_of_jobs_received_in t1 t2 t1 t2.
+
+ End ExtraDefinitions.
+
+ (* In this section, we prove some auxiliary lemmas about the service. *)
+ Section ExtraLemmas.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+
+ (* Consider any arrival sequence with consistent, nonduplicate arrivals. *)
+ Variable arr_seq: arrival_sequence Job.
+ Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.
+ Hypothesis H_arr_seq_is_a_set: arrival_sequence_is_a_set arr_seq.
+
+ (* Next, consider any uniprocessor schedule of this arrival sequence...*)
+ Variable sched: schedule Job.
+
+ (* ... where jobs do not execute before their arrival or after completion. *)
+ Hypothesis H_jobs_must_arrive_to_execute: jobs_must_arrive_to_execute job_arrival sched.
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
+
+ (* For simplicity, let's define some local names. *)
+ Let job_completed_by := completed_by job_cost sched.
+ Let arrivals_between := jobs_arrived_between arr_seq.
+
+ (* First, we prove that service is monotonic. *)
+ Lemma service_monotonic:
+ forall j t1 t2,
+ t1 <= t2 >
+ service sched j t1 <= service sched j t2.
+ Proof.
+ intros.
+ rewrite /service /service_during [X in _ <= X](@big_cat_nat _ _ _ t1) //.
+ by rewrite leq_addr.
+ Qed.
+
+ (* Next, we prove that service during can be splited into two parts. *)
+ Lemma service_during_cat:
+ forall j t t1 t2,
+ t1 <= t <= t2 >
+ service_during sched j t1 t2 =
+ service_during sched j t1 t + service_during sched j t t2.
+ Proof.
+ move => j' t t1 t2 /andP [GE LE].
+ by rewrite /service_during (@ big_cat_nat _ _ _ t).
+ Qed.
+
+ (* We prove that if in some time interval [t1,t2) a job j receives k units of service, then
+ there exists time instant t in [t1,t2) such that job is scheduled at time t and
+ service of job j within interval [t1,t) is equal to k. *)
+ Lemma incremental_service_during:
+ forall j t1 t2 k,
+ service_during sched j t1 t2 > k >
+ exists t, t1 <= t < t2 /\ scheduled_at sched j t /\ service_during sched j t1 t = k.
+ Proof.
+ intros j t1 t2 k SERV.
+ have LE: t1 <= t2.
+ { rewrite leqNgt; apply/negP; intros CONTR.
+ apply ltnW in CONTR.
+ by move: SERV; rewrite /service_during big_geq.
+ }
+ induction k.
+ { case SCHED: (scheduled_at sched j t1).
+ { exists t1; repeat split; try done.
+  apply/andP; split; first by done.
+ rewrite ltnNge; apply/negP; intros CONTR.
+ by move: SERV; rewrite/service_during big_geq.
+  by rewrite /service_during big_geq.
+ }
+ { apply negbT in SCHED.
+ move: SERV; rewrite /service /service_during; move => /sum_seq_gt0P [t [IN SCHEDt]].
+ rewrite lt0b in SCHEDt.
+ rewrite mem_iota subnKC in IN; last by done.
+ move: IN => /andP [IN1 IN2].
+ move: (exists_first_intermediate_point
+ ((fun t => scheduled_at sched j t)) t1 t IN1 SCHED SCHEDt)
+ => [x [/andP [H1 H4] [H2 H3]]].
+ exists x; repeat split; try done.
+  apply/andP; split; first by apply ltnW.
+ by apply leq_ltn_trans with t.
+  apply/eqP; rewrite big_nat_cond big1 //.
+ move => y /andP [H5 _].
+ by apply/eqP; rewrite eqb0; apply H2.
+ }
+ }
+ { feed IHk; first by apply ltn_trans with k.+1.
+ move: IHk => [t [/andP [NEQ1 NEQ2] [SCHEDt SERVk]]].
+ have SERVk1: service_during sched j t1 t.+1 = k.+1.
+ { rewrite (service_during_cat _ t).
+ rewrite SERVk [X in _ = X]addn1. apply/eqP; rewrite eqn_add2l.
+ rewrite /service_during big_nat1.
+ rewrite /service_at SCHEDt. by simpl.
+ by apply/andP; split.
+ }
+ move: SERV; rewrite (service_during_cat _ t.+1); last first.
+ { by apply/andP; split; first apply leq_trans with t. }
+ rewrite SERVk1 addn1 leq_add2l; move => SERV.
+ case SCHED: (scheduled_at sched j t.+1).
+ { exists t.+1; repeat split; try done.
+ apply/andP; split.
+  apply leq_trans with t; by done.
+  rewrite ltnNge; apply/negP; intros CONTR.
+ by move: SERV; rewrite /service_during big_geq.
+ }
+ { apply negbT in SCHED.
+ move: SERV; rewrite /service /service_during; move => /sum_seq_gt0P [x [INx SCHEDx]].
+ rewrite lt0b in SCHEDx.
+ rewrite mem_iota subnKC in INx; last by done.
+ move: INx => /andP [INx1 INx2].
+ move: (exists_first_intermediate_point
+ ((fun t => scheduled_at sched j t)) t.+1 x INx1 SCHED SCHEDx) => [y [/andP [H1 H4] [H2 H3]]].
+ exists y; repeat split; try done.
+  apply/andP; split.
+ apply leq_trans with t; first by done.
+ apply ltnW, ltn_trans with t.+1; by done.
+ by apply leq_ltn_trans with x.
+  rewrite (@big_cat_nat _ _ _ t.+1) //=; [  by apply leq_trans with t  by apply ltn_trans with t.+1].
+ unfold service_during in SERVk1; rewrite SERVk1.
+ apply/eqP.
+ rewrite {2}[k.+1]addn0 eqn_add2l.
+ rewrite big_nat_cond big1 //.
+ move => z /andP [H5 _].
+ by apply/eqP; rewrite eqb0; apply H2.
+ }
+ }
+ Qed.
+
+ (* We prove that the overall service of jobs at each time instant is at most 1. *)
+ Lemma service_of_jobs_le_1:
+ forall (t1 t2 t: time) (P: Job > bool),
+ \sum_(j < arrivals_between t1 t2  P j) service_at sched j t <= 1.
+ Proof.
+ intros t1 t2 t P.
+ case SCHED: (sched t) => [j  ]; simpl.
+ { case ARR: (j \in arrivals_between t1 t2).
+ { rewrite (big_rem j) //=; simpl.
+ rewrite /service_at /scheduled_at SCHED; simpl.
+ rewrite [1]addn0 leq_add //.
+  by rewrite eq_refl; case (P j).
+  rewrite leqn0 big1_seq; first by done.
+ move => j' /andP [_ ARRj'].
+ apply/eqP; rewrite eqb0.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; subst j'; clear CONTR.
+ rewrite rem_filter in ARRj'; last first.
+ eapply arrivals_uniq; eauto 2.
+ move: ARRj'; rewrite mem_filter; move => /andP [/negP CONTR _].
+ by apply: CONTR.
+ }
+ { apply leq_trans with 0; last by done.
+ rewrite leqn0 big1_seq; first by done.
+ move => j' /andP [_ ARRj'].
+ apply/eqP; rewrite eqb0.
+ rewrite /scheduled_at SCHED.
+ apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+ inversion CONTR; clear CONTR.
+ by subst j'; rewrite ARR in ARRj'.
+ }
+ }
+ { apply leq_trans with 0; last by done.
+ rewrite leqn0 big1_seq; first by done.
+ move => j' /andP [_ ARRj'].
+ by rewrite /service_at /scheduled_at SCHED.
+ }
+ Qed.
+
+ (* We prove that the overall service of jobs within
+ some time interval [t, t + Δ) is at most Δ. *)
+ Lemma total_service_of_jobs_le_delta:
+ forall (t Δ: time) (P: Job > bool),
+ \sum_(j < arrivals_between t (t + Δ)  P j)
+ service_during sched j t (t + Δ) <= Δ.
+ Proof.
+ intros.
+ have EQ: \sum_(t <= x < t + Δ) 1 = Δ.
+ { by rewrite big_const_nat iter_addn mul1n addn0 {2}[t]addn0 subnDl subn0. }
+ rewrite {3}EQ; clear EQ.
+ rewrite exchange_big //=.
+ rewrite leq_sum //.
+ move => t' _.
+ by apply service_of_jobs_le_1.
+ Qed.
+
+ (* In this section, we introduce a connection between the cumulative
+ service, cumulative workload, and completion of jobs. *)
+ Section WorkloadServiceAndCompletion.
+
+ (* Let P be an arbitrary predicate on jobs. *)
+ Variable P: Job > bool.
+
+ (* Consider an arbitrary time interval [t1, t2). *)
+ Variables t1 t2: time.
+
+ (* Let jobs be a set of all jobs arrived during [t1, t2). *)
+ Let jobs := arrivals_between t1 t2.
+
+ (* Next, we consider some time instant [t_compl]. *)
+ Variable t_compl: time.
+
+ (* First, we prove that the fact that the workload of [jobs] is equal to the service
+ of [jobs] implies that any job in [jobs] is completed by time t_compl. *)
+ Lemma workload_eq_service_impl_all_jobs_have_completed:
+ workload_of_jobs job_cost jobs P =
+ service_of_jobs sched jobs P t1 t_compl >
+ (forall j, j \in jobs > P j > job_completed_by j t_compl).
+ Proof.
+ unfold jobs.
+ intros.
+ move: (H0) => ARR.
+ apply (in_arrivals_implies_arrived_between job_arrival) in H0; last by done.
+ move: H0 => /andP [T1 T2].
+ have F1: forall a b, (a < b)  (a >= b).
+ { intros.
+ destruct (a < b) eqn:EQ; apply/orP.
+  by left.
+  by right; apply negbT in EQ; rewrite leqNgt.
+ }
+ move: (F1 t_compl t1) => /orP [LT  GT].
+ { rewrite /service_of_jobs /service_during in H.
+ rewrite exchange_big big_geq //= in H; last by rewrite ltnW.
+ rewrite /workload_of_jobs in H.
+ rewrite (big_rem j) ?H1 //= in H.
+ move: H => /eqP; rewrite addn_eq0; move => /andP [CZ _].
+ unfold job_completed_by, completed_by.
+ by move: CZ => /eqP CZ; rewrite CZ.
+ }
+ { unfold workload_of_jobs, service_of_jobs in H.
+ unfold job_completed_by, completed_by.
+ rewrite /service /service_during (@big_cat_nat _ _ _ t1) //=.
+ rewrite (cumulative_service_before_job_arrival_zero
+ job_arrival sched _ j 0 t1) // add0n.
+ rewrite < sum_majorant_eqn with (F1 := fun j => service_during sched j t1 t_compl)
+ (xs := arrivals_between t1 t2) (P := P); try done.
+ by intros; apply cumulative_service_le_job_cost.
+ }
+ Qed.
+
+ (* And vice versa, the fact that any job in [jobs] is completed by time t_compl
+ implies that the workload of [jobs] is equal to the service of [jobs]. *)
+ Lemma all_jobs_have_completed_impl_workload_eq_service:
+ (forall j, j \in jobs > P j > job_completed_by j t_compl) >
+ workload_of_jobs job_cost jobs P =
+ service_of_jobs sched jobs P t1 t_compl.
+ Proof.
+ unfold jobs.
+ intros.
+ have F:
+ forall j t,
+ t <= t1 >
+ (j \in arrivals_between t1 t2) >
+ service_during sched j 0 t = 0.
+ { intros j t LE ARR.
+ eapply in_arrivals_implies_arrived_between in ARR; eauto 2.
+ move: ARR => /andP [GE LT].
+ unfold service_during.
+ apply/eqP.
+ rewrite big1_seq //.
+ move => x /andP [_ ARR].
+ eapply service_before_job_arrival_zero; eauto 2.
+ move: ARR; rewrite mem_iota subn0 add0n; move => /andP [_ LTt].
+ apply leq_trans with t; first by done.
+ by apply leq_trans with t1.
+ }
+ destruct (t_compl <= t1) eqn:EQ.
+ { unfold service_of_jobs. unfold service_during.
+ rewrite exchange_big //=.
+ rewrite big_geq; last by done.
+ rewrite /workload_of_jobs big1_seq //.
+ move => j /andP [Pj ARR].
+ move: H (H _ ARR Pj) => _ H.
+ rewrite < F with (j := j) (t := t_compl); try done.
+ apply/eqP; rewrite eqn_leq; apply/andP; split.
+  by apply H.
+  by eauto 2.
+ }
+ apply/eqP; rewrite eqn_leq; apply/andP; split; first last.
+ { by apply service_of_jobs_le_workload. }
+ { unfold workload_of_jobs, service_of_jobs.
+ rewrite big_seq_cond [X in _ <= X]big_seq_cond.
+ rewrite leq_sum //.
+ move => j /andP [ARR Pj].
+ move: H (H _ ARR Pj) => _ H.
+ rewrite [service_during _ _ _ _ ]add0n.
+ rewrite (F j t1); try done.
+ rewrite (big_cat_nat) //=; last first.
+ move: EQ =>/negP /negP; rewrite ltnNge; move => EQ.
+ by apply ltnW.
+ }
+ Qed.
+
+ (* Using the lemmas above, we prove equivalence. *)
+ Lemma all_jobs_have_completed_equiv_workload_eq_service:
+ (forall j, j \in jobs > P j > job_completed_by j t_compl) <>
+ workload_of_jobs job_cost jobs P =
+ service_of_jobs sched jobs P t1 t_compl.
+ Proof.
+ split.
+  by apply all_jobs_have_completed_impl_workload_eq_service.
+  by apply workload_eq_service_impl_all_jobs_have_completed.
+ Qed.
+
+ End WorkloadServiceAndCompletion.
+
+ End ExtraLemmas.
+
End Service.
\ No newline at end of file
diff git a/model/schedule/uni/susp/last_execution.v b/model/schedule/uni/susp/last_execution.v
index 5c3f4979b16f6f0557936ed8b59aa12a4d9ad319..0a9c270c16d3eb7782f4967cc01005b228c742bf 100644
 a/model/schedule/uni/susp/last_execution.v
+++ b/model/schedule/uni/susp/last_execution.v
@@ 333,23 +333,23 @@ Module LastExecution.
Proof.
have SAME := same_service_since_last_execution.
rename H_jobs_must_arrive_to_execute into ARR.
 move: H_j_has_completed => /eqP COMP.
+ move: H_j_has_completed => COMP.
feed (exists_intermediate_point (service sched j));
first by apply service_is_a_step_function.
move => EX; feed (EX (job_arrival j) t).
 {
 feed (cumulative_service_implies_scheduled sched j 0 t);
 first by apply leq_ltn_trans with (n := s);
 last by rewrite /(service _ _ _) COMP.
+ { feed (cumulative_service_implies_scheduled sched j 0 t).
+ apply leq_ltn_trans with (n := s); first by done.
+ apply leq_trans with (job_cost j); by done.
move => [t' [/= LTt SCHED]].
apply leq_trans with (n := t'); last by apply ltnW.
by apply ARR in SCHED.
}
feed (EX s).
 {
 apply/andP; split; last by rewrite COMP.
 rewrite /service /service_during.
 by rewrite (ignore_service_before_arrival job_arrival) // big_geq.
+ { apply/andP; split.
+  rewrite /service /service_during.
+ by rewrite (ignore_service_before_arrival job_arrival) // big_geq.
+  apply leq_ltn_trans with (n := s); first by done.
+ by apply leq_trans with (job_cost j).
}
move: EX => [x_mid [_ SERV]]; exists x_mid.
by rewrite SERV SAME.
diff git a/model/schedule/uni/susp/suspension_intervals.v b/model/schedule/uni/susp/suspension_intervals.v
index 6177442acb38b7e6a67d3ebc49f09ef102a8e620..7e5851a94e22b8fc011e3be5c80a86c3e500985c 100644
 a/model/schedule/uni/susp/suspension_intervals.v
+++ b/model/schedule/uni/susp/suspension_intervals.v
@@ 1,4 +1,5 @@
Require Import rt.util.all.
+
Require Import rt.model.suspension.
Require Import rt.model.arrival.basic.job rt.model.arrival.basic.arrival_sequence.
Require Import rt.model.schedule.uni.schedule.
@@ 291,18 +292,18 @@ Module SuspensionIntervals.
intros t1 t2.
apply leq_trans with (n := \sum_(0 <= s < job_cost j)
\sum_(t1 <= t < t2  service sched j t == s) suspended_at j t).
 {
 rewrite (exchange_big_dep_nat (fun x => true)) //=.
+ { rewrite (exchange_big_dep_nat (fun x => true)) //=.
apply leq_sum; intros s _.
destruct (boolP (suspended_at j s)) as [SUSP  NOTSUSP]; last by done.
rewrite (big_rem (service sched j s)); first by rewrite eq_refl.
rewrite mem_index_iota; apply/andP; split; first by done.
rewrite ltn_neqAle; apply/andP; split;
last by apply cumulative_service_le_job_cost.
 by apply suspended_implies_not_completed in SUSP.
+ apply suspended_implies_not_completed in SUSP.
+ rewrite neq_ltn; apply/orP; left.
+ by rewrite ltnNge.
}
 {
 apply leq_sum_nat; move => s /andP [_ LT] _.
+ { apply leq_sum_nat; move => s /andP [_ LT] _.
destruct (boolP [exists t:'I_t2, (t>=t1)&& (service sched j t==s)]) as [EXALL];
last first.
{
@@ 412,18 +413,16 @@ Module SuspensionIntervals.
move: (EARLIER s LTs) => [t' EQ'].
apply leq_trans with (n := \sum_(0 <= t0 < t  (service sched j t0 == s) &&
(b t' <= t0 < b t' + n (service sched j (b t')))) 1); last first.
 {
 rewrite big_mkcond [\sum_(_ <= _ < _  _ == s)_]big_mkcond.
+ { rewrite big_mkcond [\sum_(_ <= _ < _  _ == s)_]big_mkcond.
apply leq_sum_nat; move => i /andP [_ LTi] _.
case EQi: (service sched j i == s); [rewrite andTb  by rewrite andFb].
case LE: (_ <= _ <= _); last by done.
rewrite lt0n eqb0 negbK.
apply suspended_in_suspension_interval with (t := t'); try (by done).
 rewrite neq_ltn; apply/orP; left.
 by apply: (leq_ltn_trans _ LTs); apply eq_leq; apply/eqP.
+ rewrite ltnNge.
+ by apply: (leq_ltn_trans _ LTs); apply eq_leq; apply/eqP.
}
 {
 apply leq_trans with (n := \sum_(b t'<= t0< b t'+ n (service sched j (b t')) 
+ { apply leq_trans with (n := \sum_(b t'<= t0< b t'+ n (service sched j (b t')) 
(0 <= t0 < t) && (service sched j t0 == s)) 1).
{
apply leq_trans with (n := \sum_(b t' <= t0 < b t'
@@ 438,7 +437,7 @@ Module SuspensionIntervals.
{
apply: (suspended_in_suspension_interval _ _ _ _ t');
try (by done); last by apply/andP; split.
 rewrite neq_ltn; apply/orP; left.
+ rewrite ltnNge.
rewrite (same_service_in_suspension_interval _ _ _ _ t') //;
first by rewrite EQ'.
by apply/andP; split; last by apply ltnW.
@@ 510,7 +509,7 @@ Module SuspensionIntervals.
last by apply last_execution_bounded_by_identity.
apply eq_leq, same_service_implies_same_last_execution.
rewrite /service /service_during big_nat_recr //= /service_at.
 by apply negbTE in NOTSCHED; rewrite NOTSCHED.
+ by apply negbTE in NOTSCHED; rewrite NOTSCHED addn0.
Qed.
End ExecutionBeforeSuspension.
@@ 519,4 +518,4 @@ Module SuspensionIntervals.
End DefiningSuspensionIntervals.
End SuspensionIntervals.
\ No newline at end of file
+End SuspensionIntervals.
diff git a/model/schedule/uni/sustainability.v b/model/schedule/uni/sustainability.v
new file mode 100644
index 0000000000000000000000000000000000000000..fe76fa4c7f7dbfa0f0ac2f1b99c3ccb34d131f75
 /dev/null
+++ b/model/schedule/uni/sustainability.v
@@ 0,0 +1,359 @@
+Require Import rt.util.all.
+Require Import rt.model.arrival.basic.arrival_sequence
+ rt.model.schedule.uni.schedule
+ rt.model.schedule.uni.schedulability.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+Module Sustainability.
+
+ Import ArrivalSequence UniprocessorSchedule Schedulability.
+
+ Section SustainabilityDefs.
+
+ (* Consider any job type. *)
+ Context {Job: eqType}.
+
+ Section DefiningParameters.
+
+ (** Defining Parameter Type *)
+ Section ParameterType.
+
+ (* We begin by defining the set of possible parameter labels, ... *)
+ Inductive parameter_label :=
+  JOB_ARRIVAL
+  JOB_COST
+  JOB_DEADLINE
+  JOB_JITTER
+  JOB_SUSPENSION.
+
+ (* ...which can be compared with the builtin decidable equality. *)
+ Scheme Equality for parameter_label.
+ Lemma eqlabelP: Equality.axiom parameter_label_beq.
+ Proof.
+ intros x y.
+ by destruct x; destruct y; try (by apply ReflectT); try (by apply ReflectF).
+ Qed.
+ Canonical label_eqMixin := EqMixin eqlabelP.
+ Canonical label_eqType := Eval hnf in EqType parameter_label label_eqMixin.
+
+ (* Next, we associate to each label a type of function over jobs. *)
+ Definition type_of_label (l: parameter_label) : Type :=
+ match l with
+  JOB_ARRIVAL => Job > instant
+  JOB_COST => Job > time
+  JOB_DEADLINE => Job > time
+  JOB_JITTER => Job > time
+  JOB_SUSPENSION => Job > time > duration
+ end.
+
+ (* For each function type, we also define a default value to simplify lookups. *)
+ Definition default_val (l : parameter_label) : type_of_label l :=
+ match l with
+  JOB_ARRIVAL => fun _ => 0
+  JOB_COST => fun _ => 0
+  JOB_DEADLINE => fun _ => 0
+  JOB_JITTER => fun _ => 0
+  JOB_SUSPENSION => fun _ _ => 0
+ end.
+
+ (* Finally, we define a job parameter as a pair containing a label and a function. *)
+ Record job_parameter := param
+ {
+ p_label : parameter_label;
+ p_function : type_of_label p_label
+ }.
+
+ (* With the definitions above, we can declare parameter lists as follows. *)
+ Variable example_job_cost: Job > time.
+ Variable example_job_suspension: Job > time > duration.
+ Let example_params :=
+ [:: param JOB_COST example_job_cost; param JOB_SUSPENSION example_job_suspension].
+
+ End ParameterType.
+
+ (** Looking up parameters *)
+ Section ParameterLookup.
+
+ (* By comparing labels, we define a function that finds a parameter in a list. *)
+ Definition find_param (l : parameter_label) (s : seq job_parameter) :=
+ nth (param l (default_val l)) s
+ (find (fun x => p_label x == l) s).
+
+ (* Next, we define a function that converts a given parameter p to the
+ type of label l, given a proof EQ that the labels are the same. *)
+ Let convert_parameter_type (p: job_parameter) (l: parameter_label)
+ (EQ_PROOF: p_label p = l) :=
+ eq_rect (p_label p) (fun x => type_of_label x) (p_function p) l EQ_PROOF.
+
+ (* This allows returning the function of (type_of_label l) from a parameter p.
+ (If the label of p is not l, we return a dummy default value instead.) *)
+ Definition get_param_function (l: parameter_label) (p: job_parameter) : type_of_label l :=
+ if (parameter_label_eq_dec (p_label p) l) is left EQ_PROOF then
+ convert_parameter_type p l EQ_PROOF
+ else (default_val l).
+
+ (* To conclude, we define a function that returns the function with label l from a parameter list. *)
+ Definition return_param (l: parameter_label) (s: seq job_parameter) : type_of_label l :=
+ get_param_function l (find_param l s).
+
+ (* To illustrate how these functions work, consider this simple parameter list. *)
+ Variable example_job_cost: Job > time.
+ Variable example_job_suspension: Job > time > duration.
+ Let example_params :=
+ [:: param JOB_COST example_job_cost; param JOB_SUSPENSION example_job_suspension].
+
+ (* In that case, JOB_COST returns the function example_job_cost, ...*)
+ Example return_param_works1:
+ return_param JOB_COST example_params = example_job_cost.
+ Proof. by done. Qed.
+
+ (* ...and JOB_SUSPENSION_DURATION returns the function example_job_suspension. *)
+ Example return_param_works2:
+ return_param JOB_SUSPENSION example_params = example_job_suspension.
+ Proof. by done. Qed.
+
+ End ParameterLookup.
+
+ (** Additional properties of parameter lists *)
+ Section Properties.
+
+ (* Given a set of labels, we define whether two parameter lists differ only
+ by the parameters with those labels.
+ Note: This predicate assumes that both lists have similar, unique labels. *)
+ Definition differ_only_by (variable_labels: seq parameter_label) (s1 s2: seq job_parameter) :=
+ forall (param param': job_parameter),
+ List.In param s1 >
+ List.In param' s2 >
+ p_label param = p_label param' >
+ p_label param \notin variable_labels >
+ param = param'.
+
+ (* Next, we define a function that returns the labels of a parameter list. *)
+ Definition labels_of (params: seq job_parameter) := [seq p_label p  p < params].
+
+ (* Next, we define whether a parameter list has unique labels. *)
+ Definition has_unique_labels (params: seq job_parameter) := uniq (labels_of params).
+
+ (* We also define whether a parameter list corresponds to a given set of labels. *)
+ Definition corresponding_labels (params: seq job_parameter) (labels: seq parameter_label) :=
+ forall l, l \in labels_of params <> l \in labels.
+
+ (* Finally, we prove that in any list of unique parameters, return_param always
+ returns the corresponding parameter. *)
+ Lemma found_param_label:
+ forall (params: seq job_parameter) (p: job_parameter) (label: parameter_label),
+ has_unique_labels params >
+ List.In p params >
+ p_label p = label >
+ p = param label (return_param label params).
+ Proof.
+ induction params as [ p0 params']; first by done.
+ move => p label /= /andP [NOTIN UNIQ] IN EQ /=.
+ move: IN => [EQ0  IN].
+ {
+ subst p0; rewrite /return_param /find_param /= EQ eq_refl /=.
+ by destruct p, label; simpl in *; subst.
+ }
+ {
+ rewrite /return_param /find_param /=.
+ case EQ': (_ == _); last by apply IHparams'.
+ move: EQ' => /eqP EQ'; rewrite EQ' in NOTIN.
+ move: NOTIN => /negP NOTIN; exfalso; apply NOTIN.
+ by apply/mapP2; exists p.
+ }
+ Qed.
+
+ End Properties.
+
+ End DefiningParameters.
+
+ (** Definition of sustainability for scheduling policies. *)
+ Section SustainabilityPolicy.
+
+ (* First, we define the set of possible labels for the job parameters. *)
+ Variable all_labels: seq parameter_label.
+
+ (* Next, let's consider any good schedulability property of a job, such as
+ "no deadline miss" or "response time bounded by R".
+ Given a sequence of job parameters, a schedule and a job j in this schedule,
+ the predicate indicates whether j satisfies the schedulability property. *)
+ Variable is_schedulable:
+ seq job_parameter > schedule Job > Job > bool.
+
+ (* Also, consider any predicate that, given a parameter list, states whether the arrival
+ sequence and schedule belong to a certain task model. *)
+ Variable belongs_to_task_model:
+ seq job_parameter > arrival_sequence Job > schedule Job > Prop.
+
+ (* Let sustainable_param denote the label of the parameter for which we claim sustainability. *)
+ Variable sustainable_param: parameter_label.
+
+ (* Let better_params denote any total order relation over the old and new values of the
+ sustainable parameter, i.e., it indicates: "the second parameter is better than the first".
+ For example, in many task models, lower job costs lead to better schedules, so a valid
+ predicate would be: (fun job_cost job_cost' => forall j, job_cost j >= job_cost' j). *)
+ Variable has_better_params: (type_of_label sustainable_param) >
+ (type_of_label sustainable_param) > Prop.
+
+ (* Next, we define whether the sustainable parameter becomes better when moving from list
+ params to params'. *)
+ Definition sustainable_param_becomes_better (params params': seq job_parameter) :=
+ let P := return_param sustainable_param params in
+ let P' := return_param sustainable_param params' in
+ has_better_params P P'.
+
+ Section VaryingParameters.
+
+ (* Let variable_params denote the set of parameters that are allowed to vary. *)
+ Variable variable_params: seq parameter_label.
+
+ (* Now we define whether both the sustainable and the variable parameters belong to a parameter list. *)
+ Definition sustainable_and_varying_params_in (params: seq job_parameter) :=
+ forall label,
+ label \in sustainable_param :: variable_params >
+ label \in labels_of params.
+
+ (* Next, we define whether a parameter list has consistent labels. Since
+ we'll have to quantify over many parameter lists, this prevents issues
+ with empty/invalid parameter lists. *)
+ Definition has_consistent_labels (params: seq job_parameter) :=
+ has_unique_labels params /\
+ corresponding_labels params all_labels /\
+ sustainable_and_varying_params_in params.
+
+ (* Next, we define whether all jobs sets with given params are schedulable... *)
+ Definition jobs_are_schedulable_with (params: seq job_parameter) :=
+ forall arr_seq sched j,
+ belongs_to_task_model params arr_seq sched >
+ is_schedulable params sched j.
+
+ (* ...and also define whether the job sets that only differ from the given params
+ by the 'set of variable parameters' are all schedulable. *)
+ Definition jobs_are_V_schedulable_with (params: seq job_parameter) :=
+ forall (similar_params: seq job_parameter),
+ has_consistent_labels similar_params >
+ differ_only_by variable_params params similar_params >
+ jobs_are_schedulable_with similar_params.
+
+ (* Then, we say that the scheduling policy is weaklysustainable with sustainable_param
+ and variable_params iff the following holds:
+ if jobs are Vschedulable with the original parameters, then they are also
+ schedulable with better parameters (according to the has_better_params relation). *)
+ Definition weakly_sustainable :=
+ forall (params better_params: seq job_parameter),
+ has_consistent_labels params >
+ has_consistent_labels better_params >
+ differ_only_by [::sustainable_param] params better_params >
+ sustainable_param_becomes_better params better_params >
+ jobs_are_V_schedulable_with params >
+ jobs_are_schedulable_with better_params.
+
+ (* Next, using the contrapositive of weakly_sustainable, we provide
+ an alternative definition of weak sustainability. *)
+ Section AlternativeDefinition.
+
+ (* First, let's define whether the sustainable parameter becomes
+ worse when switching from params to params'. *)
+ Definition sustainable_param_becomes_worse (params params': seq job_parameter) :=
+ let P := return_param sustainable_param params in
+ let P' := return_param sustainable_param params' in
+ has_better_params P' P.
+
+ (* Next, we define whether jobs are not schedulable with a given set of parameters. *)
+ Definition jobs_are_not_schedulable_with (params: seq job_parameter) :=
+ exists arr_seq sched j,
+ belongs_to_task_model params arr_seq sched /\
+ ~~ is_schedulable params sched j.
+
+ (* Based on that, we formalize the alternative definition of weakly sustainable. *)
+ Definition weakly_sustainable_contrapositive :=
+ forall params params_worse,
+ has_consistent_labels params >
+ has_consistent_labels params_worse >
+ jobs_are_not_schedulable_with params >
+ differ_only_by [:: sustainable_param] params params_worse >
+ sustainable_param_becomes_worse params params_worse >
+ exists params_worse',
+ has_consistent_labels params_worse' /\
+ differ_only_by variable_params params_worse params_worse' /\
+ jobs_are_not_schedulable_with params_worse'.
+
+ (* Assume De Morgan's law for propositional and predicate logic. *)
+ Hypothesis H_classical_forall_exists:
+ forall (T: Type) (P: T > Prop),
+ ~ (forall x, ~ P x) > exists x, P x.
+ Hypothesis H_classical_and_or:
+ forall (P Q: Prop), ~ (P /\ Q) > ~ P \/ ~ Q.
+
+ (* Then, we can prove the equivalence of the two definitions. *)
+ Theorem weak_sustainability_equivalence:
+ weakly_sustainable <> weakly_sustainable_contrapositive.
+ Proof.
+ rename H_classical_forall_exists into NOTALL, H_classical_and_or into ANDOR.
+ split.
+ {
+ intros WEAK params params_worse CONS CONSworse NOTSCHED DIFF WORSE.
+ apply NOTALL; intro ALL.
+ unfold weakly_sustainable in *.
+ specialize (WEAK params_worse params CONSworse CONS).
+ feed WEAK.
+ {
+ intros p p' IN IN' EQ NOTIN; symmetry.
+ apply DIFF; try by done.
+ by rewrite EQ.
+ }
+ feed WEAK; first by done.
+ feed WEAK.
+ {
+ intros params' CONS' DIFF'; specialize (ALL params').
+ apply ANDOR in ALL; move: ALL => [BUG  ALL] //.
+ apply ANDOR in ALL; move: ALL => [BUG  ALL] //.
+ unfold jobs_are_not_schedulable_with in *.
+ intros arr_seq sched j BELONGS; apply contraT; intro NOTSCHED'.
+ by exfalso; apply ALL; exists arr_seq, sched, j.
+ }
+ unfold jobs_are_schedulable_with, jobs_are_not_schedulable_with in *.
+ clear WEAK NOTSCHED.
+ move: NOTSCHED => [arr_seq [sched [j [BELONGS NOTSCHED]]]].
+ specialize (WEAK arr_seq sched j BELONGS).
+ by rewrite WEAK in NOTSCHED.
+ }
+ {
+ intros WEAK params better_params CONS CONSbetter DIFF BETTER VSCHED.
+ intros arr_seq sched j BELONGS; apply contraT; intros NOTSCHED.
+ unfold weakly_sustainable_contrapositive in *.
+ feed (WEAK better_params params); first by done.
+ feed WEAK; first by done.
+ feed WEAK; first by exists arr_seq, sched, j.
+ feed WEAK.
+ {
+ intros p p' IN IN' EQ NOTIN; symmetry.
+ apply DIFF; try by done.
+ by rewrite EQ.
+ }
+ feed WEAK; first by done.
+ move: WEAK => [params_worse' [CONS' [DIFF' NOTSCHED']]].
+ unfold jobs_are_V_schedulable_with in *.
+ specialize (VSCHED params_worse' CONS' DIFF').
+ move: NOTSCHED' => [arr_seq' [sched' [j' [BELONGS' NOTSCHED']]]].
+ specialize (VSCHED arr_seq' sched' j' BELONGS').
+ by rewrite VSCHED in NOTSCHED'.
+ }
+ Qed.
+
+ End AlternativeDefinition.
+
+ End VaryingParameters.
+
+ (* Also, we say that the scheduling policy is stronglysustainable
+ with sustainable_param iff it is weaklysustainable with
+ sustainable_param and the set of variable parameters is empty. *)
+ Definition strongly_sustainable := weakly_sustainable [::].
+
+ End SustainabilityPolicy.
+
+ End SustainabilityDefs.
+
+ Global Arguments job_parameter: clear implicits.
+
+End Sustainability.
\ No newline at end of file
diff git a/model/schedule/uni/workload.v b/model/schedule/uni/workload.v
index f877e3fe10c1bb7558c6e425b985cb2b8fc44860..65bc4254c81f3ca3463ca7e16ed2da3a4888e313 100644
 a/model/schedule/uni/workload.v
+++ b/model/schedule/uni/workload.v
@@ 77,5 +77,60 @@ Module Workload.
End PerJobPriority.
End WorkloadDefs.
+
+ (* We also define the workload of a task. *)
+ Section TaskWorkload.
+ Context {Task: eqType}.
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+ Variable job_task: Job > Task.
+
+ (* Consider any job arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* Let tsk be the task to be analyzed. *)
+ Variable tsk: Task.
+
+ (* Recall the notion of a job of task tsk. *)
+ Let of_task_tsk j := job_task j == tsk.
+
+ (* We define the task workload as the workload of jobs of task tsk. *)
+ Definition task_workload jobs := workload_of_jobs job_cost jobs of_task_tsk.
+
+ (* Next, we recall the definition of the task workload in interval [t1, t2). *)
+ Definition task_workload_between (t1 t2: time) :=
+ task_workload (jobs_arrived_between arr_seq t1 t2).
+
+ End TaskWorkload.
+
+ (* In this section, we prove a few basic lemmas about the workload. *)
+ Section BasicLemmas.
+
+ Context {Job: eqType}.
+ Variable job_arrival: Job > time.
+ Variable job_cost: Job > time.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* For simplicity, let's define some local names. *)
+ Let arrivals_between := jobs_arrived_between arr_seq.
+
+ (* We prove that workload can be splited into two parts. *)
+ Lemma workload_of_jobs_cat:
+ forall t t1 t2 P,
+ t1 <= t <= t2 >
+ workload_of_jobs job_cost (arrivals_between t1 t2) P =
+ workload_of_jobs job_cost (arrivals_between t1 t) P
+ + workload_of_jobs job_cost (arrivals_between t t2) P.
+ Proof.
+ move => t t1 t2 P /andP [GE LE].
+ rewrite /workload_of_jobs /arrivals_between.
+ by rewrite (job_arrived_between_cat _ _ t) // big_cat.
+ Qed.
+
+ End BasicLemmas.
+
End Workload.
\ No newline at end of file
diff git a/model/suspension.v b/model/suspension.v
index 88c142b3f8c363429ce5510180e960c3138bbd78..cce479f9d3f943fa8ef242a7f0df50748838fa9b 100644
 a/model/suspension.v
+++ b/model/suspension.v
@@ 15,9 +15,9 @@ Module Suspension.
(* We define job suspension as a function that takes a job in the arrival
sequence and its current service and returns how long the job must
suspend next. *)
 Definition job_suspension := Job > (* job *)
 time > (* current service *)
 time. (* duration of next suspension *)
+ Definition job_suspension := Job > (* job *)
+ time > (* current service *)
+ duration. (* duration of next suspension *)
End SuspensionTimes.
@@ 25,7 +25,7 @@ Module Suspension.
Section TotalSuspensionTime.
Context {Job: eqType}.
 Variable job_cost: Job > time.
+ Variable job_cost: Job > time.
(* Consider any job suspension function. *)
Variable next_suspension: job_suspension Job.
@@ 56,7 +56,7 @@ Module Suspension.
Let total_job_suspension := total_suspension job_cost next_suspension.
(* Next, assume that for each task a suspension bound is known. *)
 Variable suspension_bound: Task > time.
+ Variable suspension_bound: Task > duration.
(* Then, we say that the arrival sequence satisfies the dynamic
suspension model iff the total suspension time of each job is no
diff git a/restructuring/README.md b/restructuring/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..77d0dc76fa0f1b41efed7774c41cea1a67b4c56f
 /dev/null
+++ b/restructuring/README.md
@@ 0,0 +1,9 @@
+This is a workinprogress directory and part of the larger Prosa restructuring effort. As parts in Prosa are changed to comply with the “new style”, they are placed here.
+
+The behavior directory collects all definitions and basic properties of system behavior (i.e., tracebased semantics).
+
+The model directory collects all definitions and basic properties of system models (e.g., sporadic tasks, arrival curves, scheduling policies etc.)
+
+# Remarks
+
+We have chosen and applied some renaming rules for sections and definitions, cf. arrival_sequence.v and sporadic.v. Basically, we try to consistenly use `Valid*` , `*Properties` for section names about a concept `*` and `respects_*`, `valid_*` for definitions about a system model `*`.
diff git a/restructuring/analysis/schedulability.v b/restructuring/analysis/schedulability.v
new file mode 100644
index 0000000000000000000000000000000000000000..92fea8cc2ffcb4e591a477fa3797448e0b67607b
 /dev/null
+++ b/restructuring/analysis/schedulability.v
@@ 0,0 +1,108 @@
+From rt.restructuring.behavior Require Export schedule facts.completion.
+From rt.restructuring.model Require Export task.
+From rt.util Require Export seqset.
+
+Section Task.
+ Context {Task : TaskType}.
+ Context {Job: JobType}.
+
+ Context `{JobArrival Job} `{JobCost Job} `{JobTask Job Task}.
+ Context `{JobDeadline Job}.
+
+ Context {PState : Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any schedule of these jobs. *)
+ Variable sched: schedule PState.
+
+ (* Let tsk be any task that is to be analyzed. *)
+ Variable tsk: Task.
+
+ (* Then, we say that R is a responsetime bound of tsk in this schedule ... *)
+ Variable R: duration.
+
+ (* ... iff any job j of tsk in this arrival sequence has
+ completed by (job_arrival j + R). *)
+ Definition task_response_time_bound :=
+ forall j,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ job_response_time_bound sched j R.
+
+ (* We say that a task is schedulable if all its jobs meet their deadline *)
+ Definition schedulable_task :=
+ forall j,
+ arrives_in arr_seq j >
+ job_task j = tsk >
+ job_meets_deadline sched j.
+End Task.
+
+Section TaskSet.
+ Context {Task : TaskType}.
+ Context {Job: JobType}.
+
+ Context `{JobArrival Job} `{JobCost Job} `{JobTask Job Task}.
+ Context `{JobDeadline Job}.
+
+ Context {PState : Type}.
+ Context `{ProcessorState Job PState}.
+
+ Variable ts : {set Task}.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any schedule of these jobs. *)
+ Variable sched: schedule PState.
+
+ (* We say that a task set is schedulable if all its tasks are schedulable *)
+ Definition schedulable_taskset :=
+ forall tsk, tsk \in ts > schedulable_task arr_seq sched tsk.
+End TaskSet.
+
+Section Schedulability.
+ (* We can infer schedulability from a responsetime bound of a task. *)
+
+ Context {Task : TaskType}.
+ Context {Job: JobType}.
+
+ Context `{TaskDeadline Task}.
+ Context `{JobArrival Job} `{JobCost Job} `{JobTask Job Task}.
+
+ Context {PState : Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* ...and any schedule of these jobs. *)
+ Variable sched: schedule PState.
+
+ (* Assume that jobs don't execute after completion. *)
+ Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute sched.
+
+ (* Let tsk be any task that is to be analyzed. *)
+ Variable tsk: Task.
+
+ (* Given a responsetime bound of tsk in this schedule no larger than its deadline, ... *)
+ Variable R: duration.
+
+ Hypothesis H_R_le_deadline: R <= task_deadline tsk.
+ Hypothesis H_response_time_bounded: task_response_time_bound arr_seq sched tsk R.
+
+ (* ...then tsk is schedulable. *)
+ Lemma schedulability_from_response_time_bound:
+ schedulable_task arr_seq sched tsk.
+ Proof.
+ intros j ARRj JOBtsk.
+ rewrite /job_meets_deadline.
+ apply completion_monotonic with (t := job_arrival j + R);
+ [  by apply H_response_time_bounded].
+ rewrite /job_deadline leq_add2l JOBtsk.
+ by rewrite (leq_trans H_R_le_deadline).
+ Qed.
+
+End Schedulability.
diff git a/restructuring/behavior/arrival_sequence.v b/restructuring/behavior/arrival_sequence.v
new file mode 100644
index 0000000000000000000000000000000000000000..a9009a50dc0375e1d119e002b31b50e7552f3f59
 /dev/null
+++ b/restructuring/behavior/arrival_sequence.v
@@ 0,0 +1,111 @@
+From mathcomp Require Export ssreflect seq ssrnat ssrbool bigop eqtype ssrfun.
+From rt.restructuring.behavior Require Export time job.
+From rt.util Require Import notation.
+
+(* Definitions and properties of job arrival sequences. *)
+
+(* We begin by defining a job arrival sequence. *)
+Section ArrivalSequence.
+
+ (* Given any job type with decidable equality, ... *)
+ Variable Job: JobType.
+
+ (* ..., an arrival sequence is a mapping from any time to a (finite) sequence of jobs. *)
+ Definition arrival_sequence := instant > seq Job.
+
+End ArrivalSequence.
+
+(* Next, we define properties of jobs in a given arrival sequence. *)
+Section JobProperties.
+
+ (* Consider any job arrival sequence. *)
+ Context {Job: JobType}.
+ Variable arr_seq: arrival_sequence Job.
+
+ (* First, we define the sequence of jobs arriving at time t. *)
+ Definition jobs_arriving_at (t : instant) := arr_seq t.
+
+ (* Next, we say that job j arrives at a given time t iff it belongs to the
+ corresponding sequence. *)
+ Definition arrives_at (j : Job) (t : instant) := j \in jobs_arriving_at t.
+
+ (* Similarly, we define whether job j arrives at some (unknown) time t, i.e.,
+ whether it belongs to the arrival sequence. *)
+ Definition arrives_in (j : Job) := exists t, j \in jobs_arriving_at t.
+
+End JobProperties.
+
+(* Next, we define valid arrival sequences. *)
+Section ValidArrivalSequence.
+
+ (* Assume that job arrival times are known. *)
+ Context {Job: JobType}.
+ Context `{JobArrival Job}.
+
+ (* Consider any job arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* We say that arrival times are consistent if any job that arrives in the
+ sequence has the corresponding arrival time. *)
+ Definition consistent_arrival_times :=
+ forall j t,
+ arrives_at arr_seq j t > job_arrival j = t.
+
+ (* We say that the arrival sequence is a set iff it doesn't contain duplicate
+ jobs at any given time. *)
+ Definition arrival_sequence_uniq := forall t, uniq (jobs_arriving_at arr_seq t).
+
+ (* We say that the arrival sequence is valid iff it is a set and arrival times
+ are consistent *)
+ Definition valid_arrival_sequence :=
+ consistent_arrival_times /\ arrival_sequence_uniq.
+
+End ValidArrivalSequence.
+
+(* Next, we define properties of job arrival times. *)
+Section ArrivalTimeProperties.
+
+ (* Assume that job arrival times are known. *)
+ Context {Job: JobType}.
+ Context `{JobArrival Job}.
+
+ (* Let j be any job. *)
+ Variable j: Job.
+
+ (* We say that job j has arrived at time t iff it arrives at some time t_0
+ with t_0 <= t. *)
+ Definition has_arrived (t : instant) := job_arrival j <= t.
+
+ (* Next, we say that job j arrived before t iff it arrives at some time t_0
+ with t_0 < t. *)
+ Definition arrived_before (t : instant) := job_arrival j < t.
+
+ (* Finally, we say that job j arrives between t1 and t2 iff it arrives at
+ some time t with t1 <= t < t2. *)
+ Definition arrived_between (t1 t2 : instant) := t1 <= job_arrival j < t2.
+
+End ArrivalTimeProperties.
+
+(* In this section, we define arrival sequence prefixes, which are useful to
+ define (computable) properties over sets of jobs in the schedule. *)
+Section ArrivalSequencePrefix.
+
+ (* Assume that job arrival times are known. *)
+ Context {Job: JobType}.
+ Context `{JobArrival Job}.
+
+ (* Consider any job arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* By concatenation, we construct the list of jobs that arrived in the
+ interval [t1, t2). *)
+ Definition jobs_arrived_between (t1 t2 : instant) :=
+ \cat_(t1 <= t < t2) jobs_arriving_at arr_seq t.
+
+ (* Based on that, we define the list of jobs that arrived up to time t, ...*)
+ Definition jobs_arrived_up_to (t : instant) := jobs_arrived_between 0 t.+1.
+
+ (* ...and the list of jobs that arrived strictly before time t. *)
+ Definition jobs_arrived_before (t : instant) := jobs_arrived_between 0 t.
+
+End ArrivalSequencePrefix.
diff git a/restructuring/behavior/facts/all.v b/restructuring/behavior/facts/all.v
new file mode 100644
index 0000000000000000000000000000000000000000..c5b5a1ce0a1fd4700c48cddcdea049de9a2e6095
 /dev/null
+++ b/restructuring/behavior/facts/all.v
@@ 0,0 +1,5 @@
+Require Export rt.restructuring.behavior.facts.service.
+Require Export rt.restructuring.behavior.facts.completion.
+Require Export rt.restructuring.behavior.facts.ideal_schedule.
+Require Export rt.restructuring.behavior.facts.sequential.
+Require Export rt.restructuring.behavior.facts.arrivals.
diff git a/restructuring/behavior/facts/arrivals.v b/restructuring/behavior/facts/arrivals.v
new file mode 100644
index 0000000000000000000000000000000000000000..0737916d12524418b932d58325d9ae2dd2b1321c
 /dev/null
+++ b/restructuring/behavior/facts/arrivals.v
@@ 0,0 +1,157 @@
+From rt.restructuring.behavior Require Export arrival_sequence.
+From rt.util Require Import all.
+
+(* In this section, we establish useful facts about arrival sequence prefixes. *)
+Section ArrivalSequencePrefix.
+
+ (* Assume that job arrival times are known. *)
+ Context {Job: JobType}.
+ Context `{JobArrival Job}.
+
+ (* Consider any job arrival sequence. *)
+ Variable arr_seq: arrival_sequence Job.
+
+ (* By concatenation, we construct the list of jobs that arrived in the
+ interval [t1, t2). *)
+ Definition jobs_arrived_between (t1 t2 : instant) :=
+ \cat_(t1 <= t < t2) jobs_arriving_at arr_seq t.
+
+ (* Based on that, we define the list of jobs that arrived up to time t, ...*)
+ Definition jobs_arrived_up_to (t : instant) := jobs_arrived_between 0 t.+1.
+
+ (* ...and the list of jobs that arrived strictly before time t. *)
+ Definition jobs_arrived_before (t : instant) := jobs_arrived_between 0 t.
+
+ (* In this section, we prove some lemmas about arrival sequence prefixes. *)
+ Section Lemmas.
+
+ (* We begin with basic lemmas for manipulating the sequences. *)
+ Section Composition.
+
+ (* First, we show that the set of arriving jobs can be split
+ into disjoint intervals. *)
+ Lemma job_arrived_between_cat:
+ forall t1 t t2,
+ t1 <= t >
+ t <= t2 >
+ jobs_arrived_between t1 t2 = jobs_arrived_between t1 t ++ jobs_arrived_between t t2.
+ Proof.
+ unfold jobs_arrived_between; intros t1 t t2 GE LE.
+ by rewrite (@big_cat_nat _ _ _ t).
+ Qed.
+
+ (* Second, the same observation applies to membership in the set of
+ arrived jobs. *)
+ Lemma jobs_arrived_between_mem_cat:
+ forall j t1 t t2,
+ t1 <= t >
+ t <= t2 >
+ j \in jobs_arrived_between t1 t2 =
+ (j \in jobs_arrived_between t1 t ++ jobs_arrived_between t t2).
+ Proof.
+ by intros j t1 t t2 GE LE; rewrite (job_arrived_between_cat _ t).
+ Qed.
+
+ (* Third, we observe that we can grow the considered interval without
+ "losing" any arrived jobs, i.e., membership in the set of arrived jobs
+ is monotonic. *)
+ Lemma jobs_arrived_between_sub:
+ forall j t1 t1' t2 t2',
+ t1' <= t1 >
+ t2 <= t2' >
+ j \in jobs_arrived_between t1 t2 >
+ j \in jobs_arrived_between t1' t2'.
+ Proof.
+ intros j t1 t1' t2 t2' GE1 LE2 IN.
+ move: (leq_total t1 t2) => /orP [BEFORE  AFTER];
+ last by rewrite /jobs_arrived_between big_geq // in IN.
+ rewrite /jobs_arrived_between.
+ rewrite > big_cat_nat with (n := t1); [simpl  by done  by apply: (leq_trans BEFORE)].
+ rewrite mem_cat; apply/orP; right.
+ rewrite > big_cat_nat with (n := t2); [simpl  by done  by done].
+ by rewrite mem_cat; apply/orP; left.
+ Qed.
+
+ End Composition.
+
+ (* Next, we relate the arrival prefixes with job arrival times. *)
+ Section ArrivalTimes.
+
+ (* Assume that job arrival times are consistent. *)
+ Hypothesis H_consistent_arrival_times:
+ consistent_arrival_times arr_seq.
+
+ (* First, we prove that if a job belongs to the prefix
+ (jobs_arrived_before t), then it arrives in the arrival sequence. *)
+ Lemma in_arrivals_implies_arrived:
+ forall j t1 t2,
+ j \in jobs_arrived_between t1 t2 >
+ arrives_in arr_seq j.
+ Proof.
+ rename H_consistent_arrival_times into CONS.
+ intros j t1 t2 IN.
+ apply mem_bigcat_nat_exists in IN.
+ move: IN => [arr [IN _]].
+ by exists arr.
+ Qed.
+
+ (* Next, we prove that if a job belongs to the prefix
+ (jobs_arrived_between t1 t2), then it indeed arrives between t1 and
+ t2. *)
+ Lemma in_arrivals_implies_arrived_between:
+ forall j t1 t2,
+ j \in jobs_arrived_between t1 t2 >
+ arrived_between j t1 t2.
+ Proof.
+ rename H_consistent_arrival_times into CONS.
+ intros j t1 t2 IN.
+ apply mem_bigcat_nat_exists in IN.
+ move: IN => [t0 [IN /= LT]].
+ by apply CONS in IN; rewrite /arrived_between IN.
+ Qed.
+
+ (* Similarly, if a job belongs to the prefix (jobs_arrived_before t),
+ then it indeed arrives before time t. *)
+ Lemma in_arrivals_implies_arrived_before:
+ forall j t,
+ j \in jobs_arrived_before t >
+ arrived_before j t.
+ Proof.
+ intros j t IN.
+ Fail suff: arrived_between j 0 t by rewrite /arrived_between /=.
+ have: arrived_between j 0 t by apply in_arrivals_implies_arrived_between.
+ by rewrite /arrived_between /=.
+ Qed.
+
+ (* Similarly, we prove that if a job from the arrival sequence arrives
+ before t, then it belongs to the sequence (jobs_arrived_before t). *)
+ Lemma arrived_between_implies_in_arrivals:
+ forall j t1 t2,
+ arrives_in arr_seq j >
+ arrived_between j t1 t2 >
+ j \in jobs_arrived_between t1 t2.
+ Proof.
+ rename H_consistent_arrival_times into CONS.
+ move => j t1 t2 [a_j ARRj] BEFORE.
+ have SAME := ARRj; apply CONS in SAME; subst a_j.
+ by apply mem_bigcat_nat with (j := (job_arrival j)).
+ Qed.
+
+ (* Next, we prove that if the arrival sequence doesn't contain duplicate
+ jobs, the same applies for any of its prefixes. *)
+ Lemma arrivals_uniq :
+ arrival_sequence_uniq arr_seq >
+ forall t1 t2, uniq (jobs_arrived_between t1 t2).
+ Proof.
+ rename H_consistent_arrival_times into CONS.
+ unfold jobs_arrived_up_to; intros SET t1 t2.
+ apply bigcat_nat_uniq; first by done.
+ intros x t t' IN1 IN2.
+ by apply CONS in IN1; apply CONS in IN2; subst.
+ Qed.
+
+ End ArrivalTimes.
+
+ End Lemmas.
+
+End ArrivalSequencePrefix.
diff git a/restructuring/behavior/facts/completion.v b/restructuring/behavior/facts/completion.v
new file mode 100644
index 0000000000000000000000000000000000000000..4f887f65ae8ba76e0e6d4acb0a921fa31208ec43
 /dev/null
+++ b/restructuring/behavior/facts/completion.v
@@ 0,0 +1,290 @@
+From rt.restructuring.behavior Require Export schedule.
+From rt.restructuring.behavior.facts Require Export service.
+
+(** In this file, we establish basic facts about job completions. *)
+
+Section CompletionFacts.
+ (* Consider any job type,...*)
+ Context {Job: JobType}.
+ Context `{JobCost Job}.
+
+ (* ...any kind of processor model,... *)
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* ...and a given schedule. *)
+ Variable sched: schedule PState.
+
+ (* Let j be any job that is to be scheduled. *)
+ Variable j: Job.
+
+ (* We prove that after job j completes, it remains completed. *)
+ Lemma completion_monotonic:
+ forall t t',
+ t <= t' >
+ completed_by sched j t >
+ completed_by sched j t'.
+ Proof.
+ move => t t' LE. rewrite /completed_by /service => COMP.
+ apply leq_trans with (n := service_during sched j 0 t); auto.
+ by apply service_monotonic.
+ Qed.
+
+ (* We observe that being incomplete is the same as not having received
+ sufficient service yet... *)
+ Lemma less_service_than_cost_is_incomplete:
+ forall t,
+ service sched j t < job_cost j
+ <>
+ ~~ completed_by sched j t.
+ Proof.
+ move=> t. by split; rewrite /completed_by; [rewrite ltnNge //  rewrite ltnNge //].
+ Qed.
+
+ (* ...which is also the same as having positive remaining cost. *)
+ Lemma incomplete_is_positive_remaining_cost:
+ forall t,
+ ~~ completed_by sched j t
+ <>
+ remaining_cost sched j t > 0.
+ Proof.
+ move=> t. by split; rewrite /remaining_cost less_service_than_cost_is_incomplete subn_gt0 //.
+ Qed.
+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs:
+ completed_jobs_dont_execute sched.
+
+ (* Further, we note that if a job receives service at some time t, then its
+ remaining cost at this time is positive. *)
+ Lemma serviced_implies_positive_remaining_cost:
+ forall t,
+ service_at sched j t > 0 >
+ remaining_cost sched j t > 0.
+ Proof.
+ move=> t SERVICE.
+ rewrite subn_gt0 /service /service_during.
+ apply leq_trans with (\sum_(0 <= t0 < t.+1) service_at sched j t0);
+ last by rewrite H_completed_jobs.
+ by rewrite big_nat_recr //= addn1 leq_add2l.
+ Qed.
+
+ (* Consequently, if we have a have processor model where scheduled jobs
+ * necessarily receive service, we can conclude that scheduled jobs have
+ * remaining positive cost. *)
+
+ (* Assume a scheduled job always receives some positive service. *)
+ Hypothesis H_scheduled_implies_serviced:
+ forall j s, scheduled_in j s > service_in j s > 0.
+
+ (* Then a scheduled job has positive remaining cost. *)
+ Corollary scheduled_implies_positive_remaining_cost:
+ forall t,
+ scheduled_at sched j t >
+ remaining_cost sched j t > 0.
+ Proof.
+ rewrite /scheduled_at => t SCHEDULED.
+ by apply: serviced_implies_positive_remaining_cost; rewrite /service_at; apply: H_scheduled_implies_serviced.
+ Qed.
+
+ (* We also prove that a completed job cannot be scheduled... *)
+ Lemma completed_implies_not_scheduled:
+ forall t,
+ completed_by sched j t >
+ ~~ scheduled_at sched j t.
+ Proof.
+ rename H_completed_jobs into COMP.
+ unfold completed_jobs_dont_execute in *.
+ intros t COMPLETED.
+ apply/negP; red; intro SCHED.
+ have BUG := COMP j t.+1.
+ rewrite leqNgt in BUG; move: BUG => /negP BUG; apply BUG.
+ rewrite /service /service_during big_nat_recr // /= addn1.
+ apply leq_add.
+  by rewrite /(service_during sched j 0 t) /(completed_by sched j t).
+  by rewrite /service_at; apply: H_scheduled_implies_serviced; rewrite /(scheduled_at _ _ _).
+ Qed.
+
+ (* ... and that a scheduled job cannot be completed. *)
+ Lemma scheduled_implies_not_completed:
+ forall t,
+ scheduled_at sched j t >
+ ~~ completed_by sched j t.
+ Proof.
+ move=> t SCHED.
+ have REMPOS := scheduled_implies_positive_remaining_cost t SCHED.
+ rewrite /remaining_cost subn_gt0 in REMPOS.
+ by rewrite less_service_than_cost_is_incomplete.
+ Qed.
+
+ (* We further observe that [service] and [remaining_cost] are complements of
+ one another. *)
+ Lemma service_cost_invariant:
+ forall t,
+ (service sched j t) + (remaining_cost sched j t) = job_cost j.
+ Proof.
+ move=> t. rewrite /remaining_cost subnKC //.
+ Qed.
+
+End CompletionFacts.
+
+
+Section ServiceAndCompletionFacts.
+ (** In this section, we establish some facts that are really about service,
+ but are also related to completion and rely on some of the above lemmas.
+ Hence they are in this file, rather than service_facts.v. *)
+
+ (* Consider any job type,...*)
+ Context {Job: JobType}.
+ Context `{JobCost Job}.
+
+ (* ...any kind of processor model,... *)
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* ...and a given schedule. *)
+ Variable sched: schedule PState.
+
+ (* Assume that completed jobs do not execute. *)
+ Hypothesis H_completed_jobs:
+ completed_jobs_dont_execute sched.
+
+ (* Let j be any job that is to be scheduled. *)
+ Variable j: Job.
+
+ (* Assume that a scheduled job receives exactly one time unit of service. *)
+ Hypothesis H_unit_service: unit_service_proc_model.
+
+ Section GuaranteedService.
+
+ (* Assume a scheduled job always receives some positive service. *)
+ Hypothesis H_scheduled_implies_serviced:
+ forall j s, scheduled_in j s > service_in j s > 0.
+
+ (* Then we can easily show that the service never exceeds the total cost of
+ the job. *)
+ Lemma service_le_cost:
+ forall t,
+ service sched j t <= job_cost j.
+ Proof.
+ elim => [ n IH]; first by rewrite service0 //.
+ rewrite leq_eqVlt in IH.
+ case/orP: IH => [EQ  LT]; rewrite service_last_plus_before.
+  rewrite not_scheduled_implies_no_service; first by rewrite addn0 //.
+ apply: completed_implies_not_scheduled; auto. unfold unit_service_proc_model in H_unit_service.
+ move /eqP in EQ.
+ rewrite /completed_by EQ //.
+  apply leq_trans with (n := service sched j n + 1).
+ + rewrite leq_add2l /service_at //.
+ + rewrite (ltnS (service sched j n + 1) _) (addn1 (job_cost j)) ltn_add2r //.
+ Qed.
+
+ (* We show that the service received by job j in any interval is no larger
+ than its cost. *)
+ Lemma cumulative_service_le_job_cost:
+ forall t t',
+ service_during sched j t t' <= job_cost j.
+ Proof.
+ move=> t t'.
+ case/orP: (leq_total t t') => [tt'tt']; last by rewrite service_during_geq //.
+ apply leq_trans with (n := service sched j t'); last by apply: service_le_cost.
+ rewrite /service. rewrite (service_during_cat sched j 0 t t') // leq_addl //.
+ Qed.
+
+ Section ProperReleases.
+ Context `{JobArrival Job}.
+
+ (* Assume that jobs are not released early. *)
+ Hypothesis H_jobs_must_arrive:
+ jobs_must_arrive_to_execute sched.
+
+ (* We show that if job j is scheduled, then it must be pending. *)
+ Lemma scheduled_implies_pending:
+ forall t,
+ scheduled_at sched j t >
+ pending sched j t.
+ Proof.
+ move=> t SCHED.
+ rewrite /pending.
+ apply /andP; split;
+ first by apply: H_jobs_must_arrive => //.
+ apply: scheduled_implies_not_completed => //.
+ Qed.
+
+ End ProperReleases.
+ End GuaranteedService.
+
+ (* If a job isn't complete at time t, it can't be completed at time (t +
+ remaining_cost j t  1). *)
+ Lemma job_doesnt_complete_before_remaining_cost:
+ forall t,
+ ~~ completed_by sched j t >
+ ~~ completed_by sched j (t + remaining_cost sched j t  1).
+ Proof.
+ move=> t.
+ rewrite incomplete_is_positive_remaining_cost => REMCOST.
+ rewrite less_service_than_cost_is_incomplete (service_cat sched j t);
+ last by rewrite addnBA //; apply: leq_addr.
+ apply leq_ltn_trans with (n := service sched j t + remaining_cost sched j t  1).
+  by rewrite !addnBA //; rewrite leq_add2l; apply cumulative_service_le_delta; exact.
+  rewrite service_cost_invariant // subn_gt0 subKn //.
+ move: REMCOST. rewrite /remaining_cost subn_gt0 => SERVICE.
+ by apply leq_ltn_trans with (n := service sched j t).
+ Qed.
+
+End ServiceAndCompletionFacts.
+
+Section PositiveCost.
+ (** In this section, we establish facts that on jobs with nonzero costs that
+ must arrive to execute. *)
+
+ (* Consider any type of jobs with cost and arrivaltime attributes,...*)
+ Context {Job: JobType}.
+ Context `{JobCost Job}.
+ Context `{JobArrival Job}.
+
+ (* ...any kind of processor model,... *)
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* ...and a given schedule. *)
+ Variable sched: schedule PState.
+
+ (* Let j be any job that is to be scheduled. *)
+ Variable j: Job.
+
+ (* We assume that job j has positive cost, from which we can
+ infer that there always is a time in which j is pending, ... *)
+ Hypothesis H_positive_cost: job_cost j > 0.
+
+ (* ...and that jobs must arrive to execute. *)
+ Hypothesis H_jobs_must_arrive:
+ jobs_must_arrive_to_execute sched.
+
+ (* Then, we prove that the job with a positive cost
+ must be scheduled to be completed. *)
+ Lemma completed_implies_scheduled_before:
+ forall t,
+ completed_by sched j t >
+ exists t',
+ job_arrival j <= t' < t
+ /\ scheduled_at sched j t'.
+ Proof.
+ rewrite /completed_by.
+ move=> t COMPLETE.
+ have POSITIVE_SERVICE: 0 < service sched j t
+ by apply leq_trans with (n := job_cost j); auto.
+ by apply: positive_service_implies_scheduled_since_arrival; assumption.
+ Qed.
+
+ (* We also prove that the job is pending at the moment of its arrival. *)
+ Lemma job_pending_at_arrival:
+ pending sched j (job_arrival j).
+ Proof.
+ rewrite /pending.
+ apply/andP; split;
+ first by rewrite /has_arrived //.
+ rewrite /completed_by no_service_before_arrival // ltnNge //.
+ Qed.
+
+End PositiveCost.
diff git a/restructuring/behavior/facts/ideal_schedule.v b/restructuring/behavior/facts/ideal_schedule.v
new file mode 100644
index 0000000000000000000000000000000000000000..6e676e7667ad726c9494068dbcee43581696ddd9
 /dev/null
+++ b/restructuring/behavior/facts/ideal_schedule.v
@@ 0,0 +1,28 @@
+From rt.restructuring.behavior.schedule Require Import ideal.
+(* Note: we do not reexport the basic definitions to avoid littering the global
+ namespace with type class instances. *)
+
+(* In this section we show that an ideal schedule is unique at any point. *)
+Section OnlyOneJobScheduled.
+ (* Consider any job type and the ideal processor
+ model. *)
+ Context {Job: JobType}.
+
+ (* Consider an ideal schedule... *)
+ Variable sched: schedule (processor_state Job).
+
+ (* ...and two given jobs that are to be scheduled. *)
+ Variable j1 j2: Job.
+
+ (* At any time t, if both j1 and j2 are scheduled, then they must be the same
+ job. *)
+ Lemma only_one_job_scheduled:
+ forall t,
+ scheduled_at sched j1 t >
+ scheduled_at sched j2 t >
+ j1 = j2.
+ Proof.
+ by rewrite /scheduled_at=>t/eqP>/eqP[>].
+ Qed.
+
+End OnlyOneJobScheduled.
diff git a/restructuring/behavior/facts/sequential.v b/restructuring/behavior/facts/sequential.v
new file mode 100644
index 0000000000000000000000000000000000000000..1750f84635a2893f1594ced15265f46724869797
 /dev/null
+++ b/restructuring/behavior/facts/sequential.v
@@ 0,0 +1,41 @@
+From rt.restructuring.model Require Export schedule.sequential.
+
+Section ExecutionOrder.
+ (* Consider any type of job associated with any type of tasks... *)
+ Context {Job: JobType}.
+ Context {Task: TaskType}.
+ Context `{JobTask Job Task}.
+
+ (* ... with arrival times and costs ... *)
+ Context `{JobArrival Job}.
+ Context `{JobCost Job}.
+
+ (* ... and any kind of processor state model. *)
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* Assume a schedule ... *)
+ Variable sched: schedule PState.
+
+ (* in which the sequential jobs hypothesis holds. *)
+ Hypothesis H_sequential_jobs: sequential_jobs sched.
+
+
+ (* A simple corollary of this hypothesis is that the scheduler
+ executes a job with the earliest arrival time. *)
+ Corollary scheduler_executes_job_with_earliest_arrival:
+ forall j1 j2 t,
+ same_task j1 j2 >
+ ~~ completed_by sched j2 t >
+ scheduled_at sched j1 t >
+ job_arrival j1 <= job_arrival j2.
+ Proof.
+ intros ? ? t TSK NCOMPL SCHED.
+ rewrite /same_task eq_sym in TSK.
+ have SEQ := H_sequential_jobs j2 j1 t TSK.
+ rewrite leqNgt; apply/negP; intros ARR.
+ move: NCOMPL => /negP NCOMPL; apply: NCOMPL.
+ by apply SEQ.
+ Qed.
+
+End ExecutionOrder.
diff git a/restructuring/behavior/facts/service.v b/restructuring/behavior/facts/service.v
new file mode 100644
index 0000000000000000000000000000000000000000..f0d4c6e4fbdf7d04685aa27c05376b0c75a421e1
 /dev/null
+++ b/restructuring/behavior/facts/service.v
@@ 0,0 +1,583 @@
+From mathcomp Require Import ssrnat ssrbool fintype.
+From rt.restructuring.behavior Require Export schedule.
+From rt.util Require Import tactics step_function sum.
+
+(** In this file, we establish basic facts about the service received by
+ jobs. *)
+
+Section Composition.
+ (** To begin with, we provide some simple but handy rewriting rules for
+ [service] and [service_during]. *)
+
+ (* Consider any job type and any processor state. *)
+ Context {Job: JobType}.
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* For any given schedule... *)
+ Variable sched: schedule PState.
+
+ (* ...and any given job... *)
+ Variable j: Job.
+
+ (* ...we establish a number of useful rewriting rules that decompose
+ the service received during an interval into smaller intervals. *)
+
+ (* As a trivial base case, no job receives any service during an empty
+ interval. *)
+ Lemma service_during_geq:
+ forall t1 t2,
+ t1 >= t2 > service_during sched j t1 t2 = 0.
+ Proof.
+ move=> t1 t2 t1t2.
+ rewrite /service_during big_geq //.
+ Qed.
+
+ (* Equally trivially, no job has received service prior to time zero. *)
+ Corollary service0:
+ service sched j 0 = 0.
+ Proof.
+ rewrite /service service_during_geq //.
+ Qed.
+
+ (* Trivially, an interval consiting of one time unit is equivalent to
+ service_at. *)
+ Lemma service_during_instant:
+ forall t,
+ service_during sched j t t.+1 = service_at sched j t.
+ Proof.
+ move => t.
+ by rewrite /service_during big_nat_recr ?big_geq //.
+ Qed.
+
+ (* Next, we observe that we can look at the service received during an
+ interval [t1, t3) as the sum of the service during [t1, t2) and [t2, t3)
+ for any t2 \in [t1, t3]. (The "_cat" suffix denotes the concatenation of
+ the two intervals.) *)
+ Lemma service_during_cat:
+ forall t1 t2 t3,
+ t1 <= t2 <= t3 >
+ (service_during sched j t1 t2) + (service_during sched j t2 t3)
+ = service_during sched j t1 t3.
+ Proof.
+ move => t1 t2 t3 /andP [t1t2 t2t3].
+ by rewrite /service_during big_cat_nat /=.
+ Qed.
+
+ (* Since [service] is just a special case of [service_during], the same holds
+ for [service]. *)
+ Lemma service_cat:
+ forall t1 t2,
+ t1 <= t2 >
+ (service sched j t1) + (service_during sched j t1 t2)
+ = service sched j t2.
+ Proof.
+ move=> t1 t2 t1t2.
+ rewrite /service service_during_cat //.
+ Qed.
+
+ (* As a special case, we observe that the service during an interval can be
+ decomposed into the first instant and the rest of the interval. *)
+ Lemma service_during_first_plus_later:
+ forall t1 t2,
+ t1 < t2 >
+ (service_at sched j t1) + (service_during sched j t1.+1 t2)
+ = service_during sched j t1 t2.
+ Proof.
+ move => t1 t2 t1t2.
+ have TIMES: t1 <= t1.+1 <= t2 by rewrite /(_ && _) ifT //.
+ have SPLIT := service_during_cat t1 t1.+1 t2 TIMES.
+ by rewrite service_during_instant //.
+ Qed.
+
+ (* Symmetrically, we have the same for the end of the interval. *)
+ Lemma service_during_last_plus_before:
+ forall t1 t2,
+ t1 <= t2 >
+ (service_during sched j t1 t2) + (service_at sched j t2)
+ = service_during sched j t1 t2.+1.
+ Proof.
+ move=> t1 t2 t1t2.
+ rewrite (service_during_cat t1 t2 t2.+1); last by rewrite /(_ && _) ifT //.
+ rewrite service_during_instant //.
+ Qed.
+
+ (* And hence also for [service]. *)
+ Corollary service_last_plus_before:
+ forall t,
+ (service sched j t) + (service_at sched j t)
+ = service sched j t.+1.
+ Proof.
+ move=> t.
+ rewrite /service. rewrite service_during_last_plus_before //.
+ Qed.
+
+ (* Finally, we deconstruct the service received during an interval [t1, t3)
+ into the service at a midpoint t2 and the service in the intervals before
+ and after. *)
+ Lemma service_split_at_point:
+ forall t1 t2 t3,
+ t1 <= t2 < t3 >
+ (service_during sched j t1 t2) + (service_at sched j t2) + (service_during sched j t2.+1 t3)
+ = service_during sched j t1 t3.
+ Proof.
+ move => t1 t2 t3 /andP [t1t2 t2t3].
+ rewrite addnA service_during_first_plus_later// service_during_cat// /(_ && _) ifT//.
+ by exact: ltnW.
+ Qed.
+
+End Composition.
+
+
+Section UnitService.
+ (** As a common special case, we establish facts about schedules in which a
+ job receives either 1 or 0 service units at all times. *)
+
+ (* Consider any job type and any processor state. *)
+ Context {Job: JobType}.
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* We say that a kind processor state provides unit service if no
+ job ever receives more than one unit of service at any time. *)
+ Definition unit_service_proc_model := forall j s, service_in j s <= 1.
+
+ (* Let's consider a unitservice model... *)
+ Hypothesis H_unit_service: unit_service_proc_model.
+
+ (* ...and a given schedule. *)
+ Variable sched: schedule PState.
+
+ (* Let j be any job that is to be scheduled. *)
+ Variable j: Job.
+
+ (* First, we prove that the instantaneous service cannot be greater than 1, ... *)
+ Lemma service_at_most_one:
+ forall t, service_at sched j t <= 1.
+ Proof.
+ by move=> t; rewrite /service_at.
+ Qed.
+
+ (* ...which implies that the cumulative service received by job j in any
+ interval of length delta is at most delta. *)
+ Lemma cumulative_service_le_delta:
+ forall t delta,
+ service_during sched j t (t + delta) <= delta.
+ Proof.
+ unfold service_during; intros t delta.
+ apply leq_trans with (n := \sum_(t <= t0 < t + delta) 1);
+ last by simpl_sum_const; rewrite addKn leqnn.
+ by apply: leq_sum => t' _; apply: service_at_most_one.
+ Qed.
+
+ Section ServiceIsAStepFunction.
+
+ (* We show that the service received by any job j is a step function. *)
+ Lemma service_is_a_step_function:
+ is_step_function (service sched j).
+ Proof.
+ rewrite /is_step_function => t.
+ rewrite addn1 service_last_plus_before leq_add2l.
+ apply service_at_most_one.
+ Qed.
+
+ (* Next, consider any time t... *)
+ Variable t: instant.
+
+ (* ...and let s0 be any value less than the service received
+ by job j by time t. *)
+ Variable s0: duration.
+ Hypothesis H_less_than_s: s0 < service sched j t.
+
+ (* Then, we show that there exists an earlier time t0 where job j had s0
+ units of service. *)
+ Corollary exists_intermediate_service:
+ exists t0,
+ t0 < t /\
+ service sched j t0 = s0.
+ Proof.
+ feed (exists_intermediate_point (service sched j));
+ [by apply service_is_a_step_function  intros EX].
+ feed (EX 0 t); first by done.
+ feed (EX s0);
+ first by rewrite /service /service_during big_geq //.
+ by move: EX => /= [x_mid EX]; exists x_mid.
+ Qed.
+ End ServiceIsAStepFunction.
+
+End UnitService.
+
+Section Monotonicity.
+ (** We establish a basic fact about the monotonicity of service. *)
+
+ (* Consider any job type and any processor model. *)
+ Context {Job: JobType}.
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* Consider any given schedule... *)
+ Variable sched: schedule PState.
+
+ (* ...and a given job that is to be scheduled. *)
+ Variable j: Job.
+
+ (* We observe that the amount of service received is monotonic by definition. *)
+ Lemma service_monotonic:
+ forall t1 t2,
+ t1 <= t2 >
+ service sched j t1 <= service sched j t2.
+ Proof.
+ move=> t1 t2 let1t2.
+ by rewrite (service_cat sched j t1 t2 let1t2); apply: leq_addr.
+ Qed.
+
+End Monotonicity.
+
+Section RelationToScheduled.
+ (* Consider any job type and any processor model. *)
+ Context {Job: JobType}.
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* Consider any given schedule... *)
+ Variable sched: schedule PState.
+
+ (* ...and a given job that is to be scheduled. *)
+ Variable j: Job.
+
+ (* We observe that a job that isn't scheduled cannot possibly receive service. *)
+ Lemma not_scheduled_implies_no_service:
+ forall t,
+ ~~ scheduled_at sched j t > service_at sched j t = 0.
+ Proof.
+ rewrite /service_at /scheduled_at.
+ move=> t NOT_SCHED.
+ rewrite service_implies_scheduled //.
+ by apply: negbTE.
+ Qed.
+
+ (* Conversely, if a job receives service, then it must be scheduled. *)
+ Lemma service_at_implies_scheduled_at:
+ forall t,
+ service_at sched j t > 0 > scheduled_at sched j t.
+ Proof.
+ move=> t.
+ destruct (scheduled_at sched j t) eqn:SCHEDULED; first trivial.
+ rewrite not_scheduled_implies_no_service // negbT //.
+ Qed.
+
+ (* Thus, if the cumulative amount of service changes, then it must be
+ scheduled, too. *)
+ Lemma service_delta_implies_scheduled:
+ forall t,
+ service sched j t < service sched j t.+1 > scheduled_at sched j t.
+ Proof.
+ move => t.
+ rewrite service_last_plus_before {1}(addn0 (service sched j t)) ltn_add2l.
+ apply: service_at_implies_scheduled_at.
+ Qed.
+
+ (* We observe that a job receives cumulative service during some interval iff
+ it receives services at some specific time in the interval. *)
+ Lemma service_during_service_at:
+ forall t1 t2,
+ service_during sched j t1 t2 > 0
+ <>
+ exists t,
+ t1 <= t < t2 /\
+ service_at sched j t > 0.
+ Proof.
+ split.
+ {
+ move=> NONZERO.
+ case (boolP([exists t: 'I_t2,
+ (t >= t1) && (service_at sched j t > 0)])) => [EX  ALL].
+  move: EX => /existsP [x /andP [GE SERV]].
+ exists x; split; auto.
+  rewrite negb_exists in ALL; move: ALL => /forallP ALL.
+ rewrite /service_during big_nat_cond in NONZERO.
+ rewrite big1 ?ltn0 // in NONZERO => i.
+ rewrite andbT; move => /andP [GT LT].
+ specialize (ALL (Ordinal LT)); simpl in ALL.
+ rewrite GT andTb eqn0Ngt in ALL.
+ apply /eqP => //.
+ }
+ {
+ move=> [t [TT SERVICE]].
+ case (boolP (0 < service_during sched j t1 t2)) => // NZ.
+ exfalso.
+ rewrite eqn0Ngt in NZ. move/eqP: NZ.
+ rewrite big_nat_eq0 => IS_ZERO.
+ have NO_SERVICE := IS_ZERO t TT.
+ apply lt0n_neq0 in SERVICE.
+ by move/neqP in SERVICE; contradiction.
+ }
+ Qed.
+
+ (* Thus, any job that receives some service during an interval must be
+ scheduled at some point during the interval... *)
+ Corollary cumulative_service_implies_scheduled:
+ forall t1 t2,
+ service_during sched j t1 t2 > 0 >
+ exists t,
+ t1 <= t < t2 /\
+ scheduled_at sched j t.
+ Proof.
+ move=> t1 t2.
+ rewrite service_during_service_at.
+ move=> [t' [TIMES SERVICED]].
+ exists t'; split => //.
+ by apply: service_at_implies_scheduled_at.
+ Qed.
+
+ (* ...which implies that any job with positive cumulative service must have
+ been scheduled at some point. *)
+ Corollary positive_service_implies_scheduled_before:
+ forall t,
+ service sched j t > 0 > exists t', (t' < t /\ scheduled_at sched j t').
+ Proof.
+ move=> t2.
+ rewrite /service => NONZERO.
+ have EX_SCHED := cumulative_service_implies_scheduled 0 t2 NONZERO.
+ by move: EX_SCHED => [t [TIMES SCHED_AT]]; exists t; split.
+ Qed.
+
+ Section GuaranteedService.
+ (* If we can assume that a scheduled job always receives service, we can
+ further prove the converse. *)
+
+ (* Assume j always receives some positive service. *)
+ Hypothesis H_scheduled_implies_serviced:
+ forall s, scheduled_in j s > service_in j s > 0.
+
+ (* In other words, not being scheduled is equivalent to receiving zero
+ service. *)
+ Lemma no_service_not_scheduled:
+ forall t,
+ ~~ scheduled_at sched j t <> service_at sched j t = 0.
+ Proof.
+ move=> t. rewrite /scheduled_at /service_at.
+ split => [NOT_SCHED  NO_SERVICE].
+  apply negbTE in NOT_SCHED.
+ by rewrite service_implies_scheduled //.
+  apply (contra (H_scheduled_implies_serviced (sched t))).
+ by rewrite eqn0Ngt; apply /eqP => //.
+ Qed.
+
+ (* Then, if a job does not receive any service during an interval, it
+ is not scheduled. *)
+ Lemma no_service_during_implies_not_scheduled:
+ forall t1 t2,
+ service_during sched j t1 t2 = 0 >
+ forall t,
+ t1 <= t < t2 > ~~ scheduled_at sched j t.
+ Proof.
+ move=> t1 t2 ZERO_SUM t /andP [GT_t1 LT_t2].
+ rewrite no_service_not_scheduled.
+ move: ZERO_SUM.
+ rewrite /service_during big_nat_eq0 => IS_ZERO.
+ by apply (IS_ZERO t); apply /andP; split => //.
+ Qed.
+
+ (* If a job is scheduled at some point in an interval, it receivees
+ positive cumulative service during the interval... *)
+ Lemma scheduled_implies_cumulative_service:
+ forall t1 t2,
+ (exists t,
+ t1 <= t < t2 /\
+ scheduled_at sched j t) >
+ service_during sched j t1 t2 > 0.
+ Proof.
+ move=> t1 t2 [t' [TIMES SCHED]].
+ rewrite service_during_service_at.
+ exists t'; split => //.
+ move: SCHED. rewrite /scheduled_at /service_at.
+ by apply (H_scheduled_implies_serviced (sched t')).
+ Qed.
+
+ (* ...which again applies to total service, too. *)
+ Corollary scheduled_implies_nonzero_service:
+ forall t,
+ (exists t',
+ t' < t /\
+ scheduled_at sched j t') >
+ service sched j t > 0.
+ Proof.
+ move=> t [t' [TT SCHED]].
+ rewrite /service. apply scheduled_implies_cumulative_service.
+ exists t'; split => //.
+ Qed.
+
+ End GuaranteedService.
+
+ Section AfterArrival.
+ (* Futhermore, if we know that jobs are not released early, then we can
+ narrow the interval during which they must have been scheduled. *)
+
+ Context `{JobArrival Job}.
+
+ (* Assume that jobs must arrive to execute. *)
+ Hypothesis H_jobs_must_arrive:
+ jobs_must_arrive_to_execute sched.
+
+ (* We prove that any job with positive cumulative service at time [t] must
+ have been scheduled some time since its arrival and before time [t]. *)
+ Lemma positive_service_implies_scheduled_since_arrival:
+ forall t,
+ service sched j t > 0 >
+ exists t', (job_arrival j <= t' < t /\ scheduled_at sched j t').
+ Proof.
+ move=> t SERVICE.
+ have EX_SCHED := positive_service_implies_scheduled_before t SERVICE.
+ inversion EX_SCHED as [t'' [TIMES SCHED_AT]].
+ exists t''; split; last by assumption.
+ rewrite /(_ && _) ifT //.
+ move: H_jobs_must_arrive. rewrite /jobs_must_arrive_to_execute /has_arrived => ARR.
+ by apply: ARR; exact.
+ Qed.
+
+ Lemma not_scheduled_before_arrival:
+ forall t, t < job_arrival j > ~~ scheduled_at sched j t.
+ Proof.
+ move=> t EARLY.
+ apply: (contra (H_jobs_must_arrive j t)).
+ rewrite /has_arrived ltnNge //.
+ Qed.
+
+ (* We show that job j does not receive service at any time t prior to its
+ arrival. *)
+ Lemma service_before_job_arrival_zero:
+ forall t,
+ t < job_arrival j >
+ service_at sched j t = 0.
+ Proof.
+ move=> t NOT_ARR.
+ rewrite not_scheduled_implies_no_service // not_scheduled_before_arrival //.
+ Qed.
+
+ (* Note that the same property applies to the cumulative service. *)
+ Lemma cumulative_service_before_job_arrival_zero :
+ forall t1 t2 : instant,
+ t2 <= job_arrival j >
+ service_during sched j t1 t2 = 0.
+ Proof.
+ move=> t1 t2 EARLY.
+ rewrite /service_during.
+ have ZERO_SUM: \sum_(t1 <= t < t2) service_at sched j t = \sum_(t1 <= t < t2) 0;
+ last by rewrite ZERO_SUM sum0.
+ rewrite big_nat_cond [in RHS]big_nat_cond.
+ apply: eq_bigr => i /andP [TIMES _]. move: TIMES => /andP [le_t1_i lt_i_t2].
+ apply (service_before_job_arrival_zero i).
+ by apply leq_trans with (n := t2); auto.
+ Qed.
+
+ (* Hence, one can ignore the service received by a job before its arrival
+ time... *)
+ Lemma ignore_service_before_arrival:
+ forall t1 t2,
+ t1 <= job_arrival j >
+ t2 >= job_arrival j >
+ service_during sched j t1 t2 = service_during sched j (job_arrival j) t2.
+ Proof.
+ move=> t1 t2 le_t1 le_t2.
+ rewrite (service_during_cat sched j t1 (job_arrival j) t2).
+ rewrite cumulative_service_before_job_arrival_zero //.
+ by apply/andP; split; exact.
+ Qed.
+
+ (* ... which we can also state in terms of cumulative service. *)
+ Corollary no_service_before_arrival:
+ forall t,
+ t <= job_arrival j > service sched j t = 0.
+ Proof.
+ move=> t EARLY.
+ rewrite /service cumulative_service_before_job_arrival_zero //.
+ Qed.
+
+ End AfterArrival.
+
+ Section TimesWithSameService.
+ (** In this section, we prove some lemmas about time instants with same
+ service. *)
+
+ (* Consider any time instants t1 and t2... *)
+ Variable t1 t2: instant.
+
+ (* ...where t1 is no later than t2... *)
+ Hypothesis H_t1_le_t2: t1 <= t2.
+
+ (* ...and where job j has received the same amount of service. *)
+ Hypothesis H_same_service: service sched j t1 = service sched j t2.
+
+ (* First, we observe that this means that the job receives no service
+ during [t1, t2)... *)
+ Lemma constant_service_implies_no_service_during:
+ service_during sched j t1 t2 = 0.
+ Proof.
+ move: H_same_service.
+ rewrite (service_cat sched j t1 t2) // [service sched j t1 in LHS]addn0 => /eqP.
+ by rewrite eqn_add2l => /eqP //.
+ Qed.
+
+ (* ...which of course implies that it does not receive service at any
+ point, either. *)
+ Lemma constant_service_implies_not_scheduled:
+ forall t,
+ t1 <= t < t2 > service_at sched j t = 0.
+ Proof.
+ move=> t /andP [GE_t1 LT_t2].
+ move: constant_service_implies_no_service_during.
+ rewrite /service_during big_nat_eq0 => IS_ZERO.
+ apply IS_ZERO. apply /andP; split => //.
+ Qed.
+
+ (* We show that job j receives service at some point t < t1 iff j receives
+ service at some point t' < t2. *)
+ Lemma same_service_implies_serviced_at_earlier_times:
+ [exists t: 'I_t1, service_at sched j t > 0] =
+ [exists t': 'I_t2, service_at sched j t' > 0].
+ Proof.
+ apply /idP/idP => /existsP [t SERVICED].
+ {
+ have LE: t < t2
+ by apply: (leq_trans _ H_t1_le_t2) => //.
+ by apply /existsP; exists (Ordinal LE).
+ }
+ {
+ case (boolP (t < t1)) => LE.
+  by apply /existsP; exists (Ordinal LE).
+  exfalso.
+ have TIMES: t1 <= t < t2
+ by apply /andP; split => //; rewrite leqNgt //.
+ have NO_SERVICE := constant_service_implies_not_scheduled t TIMES.
+ by rewrite NO_SERVICE in SERVICED.
+ }
+ Qed.
+
+ (* Then, under the assumption that scheduled jobs receives service,
+ we can translate this into a claim about scheduled_at. *)
+
+ (* Assume j always receives some positive service. *)
+ Hypothesis H_scheduled_implies_serviced:
+ forall s, scheduled_in j s > service_in j s > 0.
+
+ (* We show that job j is scheduled at some point t < t1 iff j is scheduled
+ at some point t' < t2. *)
+ Lemma same_service_implies_scheduled_at_earlier_times:
+ [exists t: 'I_t1, scheduled_at sched j t] =
+ [exists t': 'I_t2, scheduled_at sched j t'].
+ Proof.
+ have CONV: forall B, [exists b: 'I_B, scheduled_at sched j b]
+ = [exists b: 'I_B, service_at sched j b > 0].
+ {
+ move=> B. apply/idP/idP => /existsP [b P]; apply /existsP; exists b.
+  by move: P; rewrite /scheduled_at /service_at;
+ apply (H_scheduled_implies_serviced (sched b)).
+  by apply service_at_implies_scheduled_at.
+ }
+ rewrite !CONV.
+ apply same_service_implies_serviced_at_earlier_times.
+ Qed.
+ End TimesWithSameService.
+
+End RelationToScheduled.
diff git a/restructuring/behavior/job.v b/restructuring/behavior/job.v
new file mode 100644
index 0000000000000000000000000000000000000000..9757d83038d5d42be040298bafc8df8a528402c5
 /dev/null
+++ b/restructuring/behavior/job.v
@@ 0,0 +1,17 @@
+From rt.restructuring.behavior Require Export time.
+From mathcomp Require Export eqtype.
+
+(* Throughout the library we assume that jobs have decidable equality *)
+
+Definition JobType := eqType.
+
+(* Definition of a generic type of parameter relating jobs to a discrete cost *)
+
+Class JobCost (J : JobType) := job_cost : J > duration.
+
+(* Definition of a generic type of parameter for job_arrival *)
+
+Class JobArrival (J : JobType) := job_arrival : J > instant.
+
+(* Definition of a generic type of parameter relating jobs to an absolute deadline *)
+Class JobDeadline (J : JobType) := job_deadline : J > instant.
\ No newline at end of file
diff git a/restructuring/behavior/schedule.v b/restructuring/behavior/schedule.v
new file mode 100644
index 0000000000000000000000000000000000000000..e24cf79c419d2783d9213d4dd336591cb0cf3be8
 /dev/null
+++ b/restructuring/behavior/schedule.v
@@ 0,0 +1,104 @@
+From mathcomp Require Export ssreflect ssrnat ssrbool eqtype fintype bigop.
+From rt.restructuring.behavior Require Export arrival_sequence.
+
+(* We define the notion of a generic processor state. The processor state type
+ determines aspects of the execution environment are modeled (e.g., overheads, spinning).
+ In the most simple case (i.e., Ideal.processor_state), at any time,
+ either a particular job is either scheduled or it is idle. *)
+Class ProcessorState (Job : JobType) (State : Type) :=
+ {
+ (* For a given processor state, the [scheduled_in] predicate checks whether a given
+ job is running in that state. *)
+ scheduled_in: Job > State > bool;
+ (* For a given processor state, the [service_in] function determines how much
+ service a given job receives in that state. *)
+ service_in: Job > State > nat;
+ (* For a given processor state, a job does not receive service if it is not scheduled
+ in that state *)
+ service_implies_scheduled :
+ forall j s, scheduled_in j s = false > service_in j s = 0
+ }.
+
+(* A schedule maps an instant to a processor state *)
+Definition schedule (PState : Type) := instant > PState.
+
+Section Schedule.
+ Context {Job : JobType} {PState : Type}.
+ Context `{ProcessorState Job PState}.
+
+ Variable sched : schedule PState.
+
+ (* First, we define whether a job j is scheduled at time t, ... *)
+ Definition scheduled_at (j : Job) (t : instant) := scheduled_in j (sched t).
+
+ (* ... and the instantaneous service received by
+ job j at time t. *)
+ Definition service_at (j : Job) (t : instant) := service_in j (sched t).
+
+ (* Based on the notion of instantaneous service, we define the
+ cumulative service received by job j during any interval [t1, t2). *)
+ Definition service_during (j : Job) (t1 t2 : instant) :=
+ \sum_(t1 <= t < t2) service_at j t.
+
+ (* Using the previous definition, we define the cumulative service
+ received by job j up to time t, i.e., during interval [0, t). *)
+ Definition service (j : Job) (t : instant) := service_during j 0 t.
+
+ Context `{JobCost Job}.
+ Context `{JobDeadline Job}.
+ Context `{JobArrival Job}.
+
+ (* Next, we say that job j has completed by time t if it received enough
+ service in the interval [0, t). *)
+ Definition completed_by (j : Job) (t : instant) := service j t >= job_cost j.
+
+ (* We say that R is a response time bound of a job j if j has completed
+ by R units after its arrival *)
+ Definition job_response_time_bound (j : Job) (R : duration) :=
+ completed_by j (job_arrival j + R).
+
+ (* We say that a job meets its deadline if it completes by its absolute deadline *)
+ Definition job_meets_deadline (j : Job) :=
+ completed_by j (job_deadline j).
+
+ (* Job j is pending at time t iff it has arrived but has not yet completed. *)
+ Definition pending (j : Job) (t : instant) := has_arrived j t && ~~ completed_by j t.
+
+ (* Job j is pending earlier and at time t iff it has arrived before time t
+ and has not been completed yet. *)
+ Definition pending_earlier_and_at (j : Job) (t : instant) :=
+ arrived_before j t && ~~ completed_by j t.
+
+ (* Job j is backlogged at time t iff it is pending and not scheduled. *)
+ Definition backlogged (j : Job) (t : instant) := pending j t && ~~ scheduled_at j t.
+
+ (* Let's define the remaining cost of job j as the amount of service
+ that has to be received for its completion. *)
+ Definition remaining_cost j t :=
+ job_cost j  service j t.
+
+ (* In this section, we define valid schedules. *)
+ Section ValidSchedule.
+
+ (* We define whether jobs come from some arrival sequence... *)
+ Definition jobs_come_from_arrival_sequence (arr_seq : arrival_sequence Job) :=
+ forall j t, scheduled_at j t > arrives_in arr_seq j.
+
+ (* ..., whether a job can only be scheduled if it has arrived ... *)
+ Definition jobs_must_arrive_to_execute :=
+ forall j t, scheduled_at j t > has_arrived j t.
+
+ (* ... and whether a job cannot be scheduled after it completes. *)
+ Definition completed_jobs_dont_execute :=
+ forall j t, service j t <= job_cost j.
+
+ (* We say that the schedule is valid iff
+  jobs come from some arrival sequence
+  a job can only be scheduled if it has arrived and is not completed yet *)
+ Definition valid_schedule (arr_seq : arrival_sequence Job) :=
+ jobs_come_from_arrival_sequence arr_seq /\
+ jobs_must_arrive_to_execute /\
+ completed_jobs_dont_execute.
+
+ End ValidSchedule.
+End Schedule.
diff git a/restructuring/behavior/schedule/ideal.v b/restructuring/behavior/schedule/ideal.v
new file mode 100644
index 0000000000000000000000000000000000000000..0fdfb301230b927bd6938ca2d93e8970aa614d03
 /dev/null
+++ b/restructuring/behavior/schedule/ideal.v
@@ 0,0 +1,20 @@
+From rt.restructuring.behavior Require Export schedule.
+
+(** First let us define the notion of an ideal schedule state, as done in Prosa
+ so far: either a job is scheduled or the system is idle. *)
+
+Section State.
+
+ Variable Job: JobType.
+
+ Definition processor_state := option Job.
+
+ Global Instance pstate_instance : ProcessorState Job (option Job) :=
+ {
+ scheduled_in j s := s == Some j;
+ service_in j s := s == Some j
+ }.
+ Proof.
+ by move=> j [j'>].
+ Defined.
+End State.
diff git a/restructuring/behavior/schedule/multiprocessor.v b/restructuring/behavior/schedule/multiprocessor.v
new file mode 100644
index 0000000000000000000000000000000000000000..77b1abbbf49f7523dc6c0a51a9369afa0bca79fd
 /dev/null
+++ b/restructuring/behavior/schedule/multiprocessor.v
@@ 0,0 +1,31 @@
+From mathcomp Require Export fintype.
+From rt.restructuring.behavior Require Export schedule.
+
+Section Schedule.
+
+ Variable Job: JobType.
+ Variable processor_state: Type.
+ Context `{ProcessorState Job processor_state}.
+
+ Definition processor (num_cpus: nat) := 'I_num_cpus.
+
+ Variable num_cpus : nat.
+
+ Definition identical_state := processor num_cpus > processor_state.
+
+ Global Instance multiproc_state : ProcessorState Job (identical_state) :=
+ {
+ scheduled_in j s := [exists cpu, scheduled_in j (s cpu)];
+ service_in j s := \sum_(cpu < num_cpus) service_in j (s cpu)
+ }.
+ Proof.
+ move=> j s /existsP Hsched.
+ apply/eqP.
+ rewrite sum_nat_eq0.
+ apply/forallP=>/= c.
+ rewrite service_implies_scheduled//.
+ case: (boolP (scheduled_in _ _))=>//= Habs.
+ exfalso; apply: Hsched.
+ by exists c.
+ Defined.
+End Schedule.
diff git a/restructuring/behavior/schedule/spin.v b/restructuring/behavior/schedule/spin.v
new file mode 100644
index 0000000000000000000000000000000000000000..c544709bc239b40d0c2469cf90b5a7e31e166a05
 /dev/null
+++ b/restructuring/behavior/schedule/spin.v
@@ 0,0 +1,42 @@
+From rt.restructuring.behavior Require Export schedule.
+
+(** Next we define a processor state that includes the possibility of spinning,
+ where spinning jobs do not progress (= don't get service). *)
+Section State.
+
+ Variable Job: JobType.
+
+ Inductive processor_state :=
+ Idle
+  Spin (j : Job)
+  Progress (j : Job).
+
+ Section Service.
+
+ Variable j : Job.
+
+ Definition scheduled_in (s : processor_state) : bool :=
+ match s with
+  Idle => false
+  Spin j' => j' == j
+  Progress j' => j' == j
+ end.
+
+ Definition service_in (s : processor_state) : nat :=
+ match s with
+  Idle => 0
+  Spin j' => 0
+  Progress j' => j' == j
+ end.
+
+ End Service.
+
+ Global Instance pstate_instance : ProcessorState Job (processor_state) :=
+ {
+ scheduled_in := scheduled_in;
+ service_in := service_in
+ }.
+ Proof.
+ by move=> j [j'j']//=>.
+ Defined.
+End State.
diff git a/restructuring/behavior/schedule/varspeed.v b/restructuring/behavior/schedule/varspeed.v
new file mode 100644
index 0000000000000000000000000000000000000000..138ae8d91db516567a4c5fb91bf2a401c8e94db1
 /dev/null
+++ b/restructuring/behavior/schedule/varspeed.v
@@ 0,0 +1,38 @@
+From rt.restructuring.behavior Require Export schedule.
+
+(** Next, let us define a schedule with variable execution speed. *)
+Section State.
+
+ Variable Job: JobType.
+
+ Inductive processor_state :=
+ Idle
+  Progress (j : Job) (speed : nat).
+
+ Section Service.
+
+ Variable j : Job.
+
+ Definition scheduled_in (s : processor_state) : bool :=
+ match s with
+  Idle => false
+  Progress j' _ => j' == j
+ end.
+
+ Definition service_in (s : processor_state) : nat :=
+ match s with
+  Idle => 0
+  Progress j' s => if j' == j then s else 0
+ end.
+
+ End Service.
+
+ Global Instance pstate_instance : ProcessorState Job processor_state :=
+ {
+ scheduled_in := scheduled_in;
+ service_in := service_in
+ }.
+ Proof.
+ by move=> j []//= j' s>.
+ Defined.
+End State.
diff git a/restructuring/behavior/time.v b/restructuring/behavior/time.v
new file mode 100644
index 0000000000000000000000000000000000000000..fbea1cc5ce48b83e65cd80c38e385839cf7b3c88
 /dev/null
+++ b/restructuring/behavior/time.v
@@ 0,0 +1,4 @@
+(* Time is defined as a natural number. *)
+
+Definition duration := nat.
+Definition instant := nat.
diff git a/restructuring/model/arrival/sporadic.v b/restructuring/model/arrival/sporadic.v
new file mode 100644
index 0000000000000000000000000000000000000000..7cd9dfacaa8d1a497d75887d2eea439e846d75a3
 /dev/null
+++ b/restructuring/model/arrival/sporadic.v
@@ 0,0 +1,44 @@
+From rt.restructuring.behavior Require Export arrival_sequence.
+From rt.restructuring.model Require Export task.
+
+Section TaskMinInterArrivalTime.
+ Context {T : TaskType}.
+
+ Variable (task_min_inter_arrival_time : duration).
+
+ Definition valid_task_min_inter_arrival_time :=
+ task_min_inter_arrival_time > 0.
+End TaskMinInterArrivalTime.
+
+(* Definition of a generic type of parameter for task
+ minimum inter arrival times *)
+
+Class SporadicModel (T : TaskType) :=
+ task_min_inter_arrival_time : T > duration.
+
+Section SporadicModel.
+ Context {T : TaskType} `{SporadicModel T}.
+
+ Variable ts : seq T.
+
+ Definition valid_taskset_min_inter_arrival_times :=
+ forall tsk : T,
+ tsk \in ts >
+ task_min_inter_arrival_time tsk > 0.
+
+ Context {J : JobType} `{JobTask J T} `{JobArrival J}.
+
+ Variable arr_seq : arrival_sequence J.
+
+ (* Then, we define the sporadic task model as follows.*)
+ Definition respects_sporadic_task_model :=
+ forall (j j': J),
+ j <> j' > (* Given two different jobs j and j' ... *)
+ arrives_in arr_seq j > (* ...that belong to the arrival sequence... *)
+ arrives_in arr_seq j' >
+ job_task j = job_task j' > (* ... and that are spawned by the same task, ... *)
+ job_arrival j <= job_arrival j' > (* ... if the arrival of j precedes the arrival of j' ..., *)
+ (* then the arrival of j and the arrival of j' are separated by at least one period. *)
+ job_arrival j' >= job_arrival j + task_min_inter_arrival_time (job_task j).
+
+End SporadicModel.
diff git a/restructuring/model/schedule/sequential.v b/restructuring/model/schedule/sequential.v
new file mode 100644
index 0000000000000000000000000000000000000000..bbbddef03ec512c7e4be9cc9eb45a511fb09bd75
 /dev/null
+++ b/restructuring/model/schedule/sequential.v
@@ 0,0 +1,30 @@
+From rt.restructuring.behavior Require Export schedule.
+From rt.restructuring.model Require Export task.
+
+Section PropertyOfSequentiality.
+ (* Consider any type of job associated with any type of tasks... *)
+ Context {Job: JobType}.
+ Context {Task: TaskType}.
+ Context `{JobTask Job Task}.
+
+ (* ... with arrival times and costs ... *)
+ Context `{JobArrival Job}.
+ Context `{JobCost Job}.
+
+ (* ... and any kind of processor state model. *)
+ Context {PState: Type}.
+ Context `{ProcessorState Job PState}.
+
+ (* Given a schedule ... *)
+ Variable sched: schedule PState.
+
+ (* ...we say that jobs (or, rather, tasks) are sequential if each task's jobs
+ are executed in the order they arrived. *)
+ Definition sequential_jobs :=
+ forall (j1 j2: Job) (t: instant),
+ same_task j1 j2 >
+ job_arrival j1 < job_arrival j2 >
+ scheduled_at sched j2 t >
+ completed_by sched j1 t.
+
+End PropertyOfSequentiality.
diff git a/restructuring/model/schedule/tdma.v b/restructuring/model/schedule/tdma.v
new file mode 100644
index 0000000000000000000000000000000000000000..1487078200e06e5ce86f0df8d9ad5604fc654d79
 /dev/null
+++ b/restructuring/model/schedule/tdma.v
@@ 0,0 +1,133 @@
+From rt.restructuring.behavior Require Export schedule.ideal.
+From rt.restructuring.model Require Export task.
+From rt.util Require Export seqset list.
+From mathcomp Require Export ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop div.
+
+(** In this section, we define the TDMA policy.*)
+Section TDMAPolicy.
+
+ (* The TDMA policy is based on two properties.
+ (1) Each task has a fixed, reserved time slot for execution;
+ (2) These time slots are ordered in sequence to form a TDMA cycle, which repeats along the timeline.
+ An example of TDMA schedule is illustrated in the following.
+ ______________________________
+  s1  s2 s3 s1  s2 s3...
+ >
+ 0 t
+ *)
+
+ Variable Task: eqType.
+ (* With each task, we associate the duration of the corresponding TDMA slot. *)
+ Definition TDMA_slot := Task > duration.
+
+ (* Moreover, within each TDMA cycle, task slots are ordered according to some relation.
+ (i.e, slot_order slot1 slot2 means that slot1 comes before slot2 in a TDMA cycle) *)
+ Definition TDMA_slot_order := rel Task.
+
+End TDMAPolicy.
+
+Class TDMAPolicy (T : TaskType) :=
+ { task_time_slot : TDMA_slot T;
+ slot_order : TDMA_slot_order T }.
+
+(* First, we define the properties of a valid TDMA policy. *)
+Section ValidTDMAPolicy.
+
+ Context {Task : eqType}.
+
+ (* Consider any task set ts... *)
+ Variable ts : {set Task}.
+
+ (* ...and a TDMA policy. *)
+ Context `{TDMAPolicy Task}.
+
+ (* Time slot order must be transitive... *)
+ Definition transitive_slot_order := transitive slot_order.
+
+ (* ..., totally ordered over the task set... *)
+ Definition total_slot_order :=
+ total_over_list slot_order ts.
+
+ (* ... and antisymmetric over task set. *)
+ Definition antisymmetric_slot_order :=
+ antisymmetric_over_list slot_order ts.
+
+ (* A valid time slot must be positive *)
+ Definition valid_time_slot :=
+ forall tsk, tsk \in ts > task_time_slot tsk > 0.
+
+ Definition valid_TDMAPolicy :=
+ transitive_slot_order /\ total_slot_order /\ antisymmetric_slot_order /\ valid_time_slot.
+
+End ValidTDMAPolicy.
+
+(** In this section, we define functions on a TDMA policy *)
+Section TDMADefinitions.
+
+ Context {Task : eqType}.
+
+ (* Consider any task set ts... *)
+ Variable ts : {set Task}.
+
+ (* ...and a TDMA policy. *)
+ Context `{TDMAPolicy Task}.
+
+ (* We define the TDMA cycle as the sum of all the tasks' time slots *)
+ Definition TDMA_cycle:=
+ \sum_(tsk < ts) task_time_slot tsk.
+
+ (* We define the function returning the slot offset for each task:
+ i.e., the distance between the start of the TDMA cycle and
+ the start of the task time slot *)
+ Definition task_slot_offset (tsk : Task) :=
+ \sum_(prev_task < ts  slot_order prev_task tsk && (prev_task != tsk)) task_time_slot prev_task.
+
+ (* The following function tests whether a task is in its time slot at instant t *)
+ Definition task_in_time_slot (tsk : Task) (t:instant):=
+ ((t + TDMA_cycle  (task_slot_offset tsk)%% TDMA_cycle) %% TDMA_cycle)
+ < (task_time_slot tsk).
+End TDMADefinitions.
+
+Section TDMASchedule.
+
+ Context {Task : TaskType} {Job : JobType}.
+
+ Context `{JobArrival Job} `{JobCost Job} `{JobTask Job Task}.
+
+ (* Consider any job arrival sequence... *)
+ Variable arr_seq : arrival_sequence Job.
+
+ (* ..., any uniprocessor ideal schedule ... *)
+ Variable sched : schedule (option Job).
+
+ (* ... and any sporadic task set. *)
+ Variable ts: {set Task}.
+
+ Context `{TDMAPolicy Task}.
+
+ (* In order to characterize a TDMA policy, we first define whether a job is executing its TDMA slot at time t. *)
+ Definition job_in_time_slot (job:Job) (t:instant):=
+ task_in_time_slot ts (job_task job) t.
+
+ (* We say that a TDMA policy is respected by the schedule iff
+ 1. when a job is scheduled at time t, then the corresponding task
+ is also in its own time slot... *)
+ Definition sched_implies_in_slot j t:=
+ scheduled_at sched j t > job_in_time_slot j t.
+
+ (* 2. when a job is backlogged at time t,the corresponding task
+ isn't in its own time slot or another previous job of the same task is scheduled *)
+ Definition backlogged_implies_not_in_slot_or_other_job_sched j t:=
+ backlogged sched j t >
+ ~ job_in_time_slot j t \/
+ exists j_other, arrives_in arr_seq j_other/\
+ job_arrival j_other < job_arrival j/\
+ job_task j = job_task j_other/\
+ scheduled_at sched j_other t.
+
+ Definition respects_TDMA_policy:=
+ forall (j:Job) (t:instant),
+ arrives_in arr_seq j >
+ sched_implies_in_slot j t /\
+ backlogged_implies_not_in_slot_or_other_job_sched j t.
+End TDMASchedule.
\ No newline at end of file
diff git a/restructuring/model/schedule/tdma_facts.v b/restructuring/model/schedule/tdma_facts.v
new file mode 100644
index 0000000000000000000000000000000000000000..bb2d6192e130f6083b0c40cefea4445413056392
 /dev/null
+++ b/restructuring/model/schedule/tdma_facts.v
@@ 0,0 +1,144 @@
+From rt.restructuring.model Require Export schedule.tdma.
+From rt.util Require Import all.
+
+(** In this section, we define the properties of TDMA and prove some basic lemmas. *)
+Section TDMAFacts.
+ Context {Task:eqType}.
+
+ (* Consider any task set ts... *)
+ Variable ts: {set Task}.
+
+ (* ... with a TDMA policy *)
+ Context `{TDMAPolicy Task}.
+
+ Section TimeSlotFacts.
+ (* Consider any task in ts*)
+ Variable task: Task.
+ Hypothesis H_task_in_ts: task \in ts.
+
+ (* Assume task_time_slot is valid time slot*)
+ Hypothesis time_slot_positive:
+ valid_time_slot ts.
+
+ (* Obviously, the TDMA cycle is greater or equal than any task time slot which is
+ in TDMA cycle *)
+ Lemma TDMA_cycle_ge_each_time_slot:
+ TDMA_cycle ts >= task_time_slot task.
+ Proof.
+ rewrite /TDMA_cycle (big_rem task) //.
+ apply:leq_trans; last by exact: leq_addr.
+ by apply leqnn.
+ Qed.
+
+ (* Thus, a TDMA cycle is always positive *)
+ Lemma TDMA_cycle_positive:
+ TDMA_cycle ts > 0.
+ Proof.
+ move:time_slot_positive=>/(_ task H_task_in_ts)/leq_trans;apply;apply TDMA_cycle_ge_each_time_slot.
+ Qed.
+
+ (* Slot offset is less then cycle *)
+ Lemma Offset_lt_cycle:
+ task_slot_offset ts task < TDMA_cycle ts.
+ Proof.
+ rewrite /task_slot_offset /TDMA_cycle big_mkcond.
+ apply leq_ltn_trans with (n:=\sum_(prev_task < ts )if prev_task!=task then task_time_slot prev_task else 0).
+  apply leq_sum. intros* T. case (slot_order i task);auto.
+  rewrite big_mkcond (bigD1_seq task)?set_uniq//=.
+ rewrite subn_gt0 addnBA. rewrite subnn addn0 //.
+ exact: time_slot_positive.
+ easy.
+ Qed.
+
+ (* For a task, the sum of its slot offset and its time slot is
+ less then or equal to cycle. *)
+ Lemma Offset_add_slot_leq_cycle:
+ task_slot_offset ts task + task_time_slot task <= TDMA_cycle ts.
+ Proof.
+ rewrite /task_slot_offset /TDMA_cycle.
+ rewrite addnC (bigD1_seq task) //=. rewrite leq_add2l.
+ rewrite big_mkcond.
+ replace (\sum_(i < ts  i != task) task_time_slot i)
+ with (\sum_(i < ts ) if i != task then task_time_slot i else 0).
+ apply leq_sum. intros*T. case (slot_order i task);auto.
+ by rewrite big_mkcond. apply (set_uniq ts).
+ Qed.
+ End TimeSlotFacts.
+
+ (* Now we prove that no two tasks share the same time slot at any time. *)
+ Section TimeSlotOrderFacts.
+ (* Consider any task in ts*)
+ Variable task: Task.
+ Hypothesis H_task_in_ts: task \in ts.
+
+ (* Assume task_time_slot is valid time slot*)
+ Hypothesis time_slot_positive:
+ valid_time_slot ts.
+
+ (* Assume that slot order is total... *)
+ Hypothesis slot_order_total:
+ total_slot_order ts.
+
+ (*..., antisymmetric... *)
+ Hypothesis slot_order_antisymmetric:
+ antisymmetric_slot_order ts.
+
+ (*... and transitive. *)
+ Hypothesis slot_order_transitive:
+ transitive_slot_order.
+
+ (* Then, we can prove that the difference value between two offsets is
+ at least a slot *)
+ Lemma relation_offset:
+ forall tsk1 tsk2, tsk1 \in ts >
+ tsk2 \in ts >
+ slot_order tsk1 tsk2 >
+ tsk1 != tsk2 >
+ task_slot_offset ts tsk2 >=
+ task_slot_offset ts tsk1 + task_time_slot tsk1 .
+ Proof.
+ intros* IN1 IN2 ORDER NEQ.
+ rewrite /task_slot_offset big_mkcond addnC/=.
+ replace (\sum_(tsk < ts  slot_order tsk tsk2 && (tsk != tsk2)) task_time_slot tsk)
+ with (task_time_slot tsk1 + \sum_(tsk < ts )if slot_order tsk tsk2 && (tsk != tsk1) && (tsk!=tsk2) then task_time_slot tsk else O).
+ rewrite leq_add2l. apply leq_sum_seq. intros* IN T.
+ case (slot_order i tsk1)eqn:SI2;auto. case (i==tsk1)eqn:IT2;auto;simpl.
+ case (i==tsk2)eqn:IT1;simpl;auto.
+  by move/eqP in IT1;rewrite IT1 in SI2;apply slot_order_antisymmetric in ORDER;auto;apply ORDER in SI2;move/eqP in NEQ.
+  by rewrite (slot_order_transitive _ _ _ SI2 ORDER).
+  symmetry. rewrite big_mkcond /=. rewrite>bigD1_seq with (j:=tsk1);auto;last by apply (set_uniq ts).
+ move/eqP /eqP in ORDER. move/eqP in NEQ. rewrite ORDER //=. apply /eqP.
+ have TS2: (tsk1 != tsk2) = true . apply /eqP;auto. rewrite TS2.
+ rewrite eqn_add2l. rewrite big_mkcond. apply/eqP. apply eq_bigr;auto.
+ intros* T. case(i!=tsk1);case (slot_order i tsk2);case (i!=tsk2) ;auto.
+ Qed.
+
+ (* Then, we proved that no two tasks share the same time slot at any time. *)
+ Lemma task_in_time_slot_uniq:
+ forall tsk1 tsk2 t, tsk1 \in ts > task_time_slot tsk1 > 0 >
+ tsk2 \in ts > task_time_slot tsk2 > 0 >
+ task_in_time_slot ts tsk1 t >
+ task_in_time_slot ts tsk2 t >
+ tsk1 = tsk2.
+ Proof.
+ intros* IN1 SLOT1 IN2 SLOT2.
+ rewrite /task_in_time_slot.
+ set cycle:=TDMA_cycle ts.
+ set O1:= task_slot_offset ts tsk1.
+ set O2:= task_slot_offset ts tsk2.
+ have CO1: O1 < cycle by apply Offset_lt_cycle.
+ have CO2: O2 < cycle by apply Offset_lt_cycle.
+ have C: cycle > 0 by apply (TDMA_cycle_positive tsk1).
+ have GO1:O1 %% cycle = O1 by apply modn_small,Offset_lt_cycle. rewrite GO1.
+ have GO2:O2 %% cycle = O2 by apply modn_small,Offset_lt_cycle. rewrite GO2.
+ have SO1:O1 + task_time_slot tsk1 <= cycle by apply (Offset_add_slot_leq_cycle tsk1).
+ have SO2:O2 + task_time_slot tsk2 <= cycle by apply (Offset_add_slot_leq_cycle tsk2).
+ repeat rewrite mod_elim;auto.
+ case (O1 <= t%%cycle)eqn:O1T;case (O2 <= t %%cycle)eqn:O2T;intros G1 G2;try ssromega.
+ apply ltn_subLR in G1;apply ltn_subLR in G2. case (tsk1==tsk2) eqn:NEQ;move/eqP in NEQ;auto.
+ destruct (slot_order_total tsk1 tsk2) as [order order];auto;apply relation_offset in order;
+ fold O1 O2 in order;try ssromega;auto. by move/eqP in NEQ. apply /eqP;auto.
+ Qed.
+
+ End TimeSlotOrderFacts.
+End TDMAFacts.
\ No newline at end of file
diff git a/restructuring/model/task.v b/restructuring/model/task.v
new file mode 100644
index 0000000000000000000000000000000000000000..f530b004499d9e3fc9154a77e604229c4e940d08
 /dev/null
+++ b/restructuring/model/task.v
@@ 0,0 +1,32 @@
+From mathcomp Require Export ssrbool.
+From rt.restructuring.behavior Require Export job.
+
+(* Throughout the library we assume that tasks have decidable equality *)
+
+Definition TaskType := eqType.
+
+(* Definition of a generic type of parameter relating jobs to tasks *)
+
+Class JobTask (J : JobType) (T : TaskType) := job_task : J > T.
+
+Section SameTask.
+ (* For any type of job associated with any type of tasks... *)
+ Context {Job: JobType}.
+ Context {Task: TaskType}.
+ Context `{JobTask Job Task}.
+
+ (* ... we say that two jobs j1 and j2 are from the same task iff job_task j1
+ is equal to job_task j2. *)
+ Definition same_task j1 j2 := job_task j1 == job_task j2.
+
+End SameTask.
+
+(* Definition of a generic type of parameter for task deadlines *)
+Class TaskDeadline (Task : TaskType) := task_deadline : Task > duration.
+
+(* Given task deadlines and a mapping from jobs to tasks we provide a generic definition of job_deadline *)
+
+Instance job_deadline_from_task_deadline
+ (Job : JobType) (Task : TaskType)
+ `{TaskDeadline Task} `{JobArrival Job} `{JobTask Job Task} :
+ JobDeadline Job := fun j => job_arrival j + task_deadline (job_task j).
diff git a/restructuring/model/task_cost.v b/restructuring/model/task_cost.v
new file mode 100644
index 0000000000000000000000000000000000000000..014720c3dba960e2ac90995e3dc4b2b988f0ca3c
 /dev/null
+++ b/restructuring/model/task_cost.v
@@ 0,0 +1,35 @@
+From rt.restructuring.behavior Require Export arrival_sequence.
+From rt.restructuring.model Require Export task.
+
+Section TaskCost.
+ Context {T : TaskType}.
+
+ Variable (task_cost : duration).
+
+ Definition valid_task_cost := task_cost > 0.
+End TaskCost.
+
+(* Definition of a generic type of parameter for task cost *)
+
+Class TaskCost (T : TaskType) := task_cost : T > duration.
+
+Section TasksetCosts.
+ Context {T : TaskType} `{TaskCost T}.
+
+ Variable ts : seq T.
+
+ Definition valid_taskset_costs :=
+ forall tsk : T,
+ tsk \in ts >
+ task_cost tsk > 0.
+
+ Context {J : JobType} `{JobTask J T} `{JobCost J}.
+
+ Variable arr_seq : arrival_sequence J.
+
+ Definition respects_taskset_costs :=
+ forall j,
+ arrives_in arr_seq j >
+ job_cost j <= task_cost (job_task j).
+
+End TasksetCosts.
diff git a/scripts/knownlongproofs.json b/scripts/knownlongproofs.json
new file mode 100644
index 0000000000000000000000000000000000000000..ad88b329ac7e6269223fd5e35192bd3771fb0b5b
 /dev/null
+++ b/scripts/knownlongproofs.json
@@ 0,0 +1,314 @@
+{
+ "manual_exceptions": {
+ },
+ "legacy_proofs": {
+ "./analysis/apa/bertogna_edf_comp.v": {
+ "bertogna_edf_comp_f_increases": 53,
+ "bertogna_edf_comp_iteration_preserves_order": 159,
+ "bertogna_edf_comp_rt_grows_too_much": 99,
+ "edf_claimed_bounds_finds_fixed_point_of_list": 76
+ },
+ "./analysis/apa/bertogna_edf_theory.v": {
+ "bertogna_cirinei_response_time_bound_edf": 49,
+ "bertogna_edf_all_cpus_in_affinity_busy": 52,
+ "bertogna_edf_all_cpus_in_subaffinity_busy": 51,
+ "bertogna_edf_alpha'_is_full": 106,
+ "bertogna_edf_interference_by_different_tasks": 43,
+ "bertogna_edf_interference_in_non_full_processors": 133,
+ "bertogna_edf_sum_exceeds_total_interference": 43
+ },
+ "./analysis/apa/bertogna_fp_comp.v": {
+ "fp_analysis_yields_response_time_bounds": 107
+ },
+ "./analysis/apa/bertogna_fp_theory.v": {
+ "bertogna_cirinei_response_time_bound_fp": 47,
+ "bertogna_fp_all_cpus_in_affinity_busy": 54,
+ "bertogna_fp_all_cpus_in_subaffinity_busy": 53,
+ "bertogna_fp_alpha'_is_full": 143,
+ "bertogna_fp_interference_by_different_tasks": 42,
+ "bertogna_fp_interference_in_non_full_processors": 149,
+ "bertogna_fp_sum_exceeds_total_interference": 42,
+ "bertogna_fp_workload_bounds_interference": 44
+ },
+ "./analysis/apa/interference_bound_edf.v": {
+ "interference_bound_edf_holds_for_single_job_that_completes_on_time": 86,
+ "interference_bound_edf_many_periods_in_between": 40
+ },
+ "./analysis/apa/workload_bound.v": {
+ "W_monotonic": 51,
+ "workload_bound_service_of_first_and_last_jobs": 45,
+ "workload_bounded_by_W": 48
+ },
+ "./analysis/global/basic/bertogna_edf_comp.v": {
+ "bertogna_edf_comp_f_increases": 53,
+ "bertogna_edf_comp_iteration_preserves_order": 160,
+ "bertogna_edf_comp_rt_grows_too_much": 100,
+ "edf_claimed_bounds_finds_fixed_point_of_list": 76
+ },
+ "./analysis/global/basic/bertogna_edf_theory.v": {
+ "bertogna_cirinei_response_time_bound_edf": 50,
+ "bertogna_edf_interference_by_different_tasks": 43,
+ "bertogna_edf_interference_in_non_full_processors": 129
+ },
+ "./analysis/global/basic/bertogna_fp_comp.v": {
+ "fp_analysis_yields_response_time_bounds": 105
+ },
+ "./analysis/global/basic/bertogna_fp_theory.v": {
+ "bertogna_cirinei_response_time_bound_fp": 48,
+ "bertogna_fp_interference_by_different_tasks": 42,
+ "bertogna_fp_interference_in_non_full_processors": 164,
+ "bertogna_fp_workload_bounds_interference": 45
+ },
+ "./analysis/global/basic/interference_bound_edf.v": {
+ "interference_bound_edf_holds_for_single_job_that_completes_on_time": 92,
+ "interference_bound_edf_many_periods_in_between": 40
+ },
+ "./analysis/global/basic/workload_bound.v": {
+ "W_monotonic": 51,
+ "workload_bound_service_of_first_and_last_jobs": 46,
+ "workload_bounded_by_W": 48
+ },
+ "./analysis/global/jitter/bertogna_edf_comp.v": {
+ "bertogna_edf_comp_f_increases": 53,
+ "bertogna_edf_comp_iteration_preserves_order": 160,
+ "bertogna_edf_comp_rt_grows_too_much": 100,
+ "edf_claimed_bounds_finds_fixed_point_of_list": 77
+ },
+ "./analysis/global/jitter/bertogna_edf_theory.v": {
+ "bertogna_cirinei_response_time_bound_edf": 60,
+ "bertogna_edf_interference_by_different_tasks": 63,
+ "bertogna_edf_interference_in_non_full_processors": 125
+ },
+ "./analysis/global/jitter/bertogna_fp_comp.v": {
+ "fp_analysis_yields_response_time_bounds": 120
+ },
+ "./analysis/global/jitter/bertogna_fp_theory.v": {
+ "bertogna_cirinei_response_time_bound_fp": 49,
+ "bertogna_fp_all_cpus_are_busy": 40,
+ "bertogna_fp_interference_by_different_tasks": 54,
+ "bertogna_fp_interference_in_non_full_processors": 173,
+ "bertogna_fp_workload_bounds_interference": 46
+ },
+ "./analysis/global/jitter/interference_bound_edf.v": {
+ "interference_bound_edf_holds_for_single_job_that_completes_on_time": 123,
+ "interference_bound_edf_holds_for_single_job_with_small_slack": 55,
+ "interference_bound_edf_j_fst_completed_on_time": 46,
+ "interference_bound_edf_many_periods_in_between": 49
+ },
+ "./analysis/global/jitter/workload_bound.v": {
+ "W_monotonic": 51,
+ "workload_bound_many_periods_in_between": 41,
+ "workload_bound_n_k_covers_middle_jobs": 40,
+ "workload_bound_service_of_first_and_last_jobs": 50,
+ "workload_bounded_by_W": 48
+ },
+ "./analysis/global/parallel/bertogna_edf_comp.v": {
+ "bertogna_edf_comp_f_increases": 53,
+ "bertogna_edf_comp_iteration_preserves_order": 159,
+ "bertogna_edf_comp_rt_grows_too_much": 96,
+ "edf_claimed_bounds_finds_fixed_point_of_list": 76
+ },
+ "./analysis/global/parallel/bertogna_edf_theory.v": {
+ "bertogna_cirinei_response_time_bound_edf": 49,
+ "bertogna_edf_interference_on_all_cpus": 75
+ },
+ "./analysis/global/parallel/bertogna_fp_comp.v": {
+ "fp_analysis_yields_response_time_bounds": 98
+ },
+ "./analysis/global/parallel/bertogna_fp_theory.v": {
+ "bertogna_cirinei_response_time_bound_fp": 41,
+ "bertogna_fp_all_cpus_are_busy": 78
+ },
+ "./analysis/global/parallel/interference_bound_edf.v": {
+ "interference_bound_edf_many_periods_in_between": 40,
+ "interference_bound_edf_n_k_covers_all_jobs": 45
+ },
+ "./analysis/uni/arrival_curves/workload_bound.v": {
+ "total_workload_le_total_rbf": 45,
+ "total_workload_le_total_rbf'": 41,
+ "total_workload_le_total_rbf''": 41
+ },
+ "./analysis/uni/basic/tdma_wcrt_analysis.v": {
+ "formula_not_sched_St": 45,
+ "formula_sched_St": 100,
+ "response_time_le_WCRT": 52
+ },
+ "./analysis/uni/susp/dynamic/jitter/jitter_schedule_properties.v": {
+ "sched_jitter_does_not_pick_j": 50,
+ "sched_jitter_respects_policy": 77
+ },
+ "./analysis/uni/susp/dynamic/jitter/jitter_schedule_service.v": {
+ "jitter_reduction_inductive_step_case2": 96,
+ "jitter_reduction_less_job_service_before_interval_case5": 44,
+ "jitter_reduction_service_jitter": 51
+ },
+ "./analysis/uni/susp/dynamic/jitter/taskset_rta.v": {
+ "valid_response_time_bound_of_tsk_i": 52
+ },
+ "./analysis/uni/susp/dynamic/oblivious/reduction.v": {
+ "sched_new_completed_jobs_dont_execute": 42
+ },
+ "./analysis/uni/susp/sustainability/allcosts/main_claim.v": {
+ "policy_is_weakly_sustainable": 63
+ },
+ "./analysis/uni/susp/sustainability/allcosts/reduction_properties.v": {
+ "executes_before_suspension_in_sched_new": 42,
+ "sched_new_has_shorter_total_suspension": 43,
+ "sched_new_respects_policy": 77,
+ "sched_new_work_conserving": 63,
+ "suspended_in_sched_new_no_service_since_execution": 46,
+ "suspended_in_sched_new_suspension_starts_no_earlier": 56
+ },
+ "./analysis/uni/susp/sustainability/singlecost/reduction_properties.v": {
+ "sched_susp_highercost_depends_only_on_prefix": 56,
+ "sched_susp_highercost_same_schedule": 81
+ },
+ "./implementation/apa/bertogna_fp_example.v": {
+ "schedulability_test_succeeds": 87
+ },
+ "./implementation/apa/schedule.v": {
+ "scheduler_has_no_duplicate_jobs": 55,
+ "scheduler_mapping_is_work_conserving": 46,
+ "scheduler_priority": 113
+ },
+ "./implementation/global/basic/bertogna_fp_example.v": {
+ "schedulability_test_succeeds": 40
+ },
+ "./implementation/global/jitter/bertogna_fp_example.v": {
+ "schedulability_test_succeeds": 41
+ },
+ "./implementation/global/parallel/bertogna_fp_example.v": {
+ "schedulability_test_succeeds": 59
+ },
+ "./implementation/uni/basic/fp_rta_example.v": {
+ "RTA_yields_these_bounds": 45
+ },
+ "./implementation/uni/basic/schedule_tdma.v": {
+ "respects_FIFO": 45
+ },
+ "./implementation/uni/basic/tdma_rta_example.v": {
+ "respects_TDMA_policy": 43
+ },
+ "./implementation/uni/jitter/fp_rta_example.v": {
+ "RTA_yields_these_bounds": 52
+ },
+ "./implementation/uni/susp/dynamic/oblivious/fp_rta_example.v": {
+ "RTA_yields_these_bounds": 51
+ },
+ "./implementation/uni/susp/schedule.v": {
+ "scheduler_depends_only_on_prefix": 52
+ },
+ "./model/schedule/global/basic/constrained_deadlines.v": {
+ "platform_cpus_busy_with_interfering_tasks": 65,
+ "platform_fp_cpus_busy_with_interfering_tasks": 82
+ },
+ "./model/schedule/global/basic/platform.v": {
+ "work_conserving_eq_work_conserving_count": 67
+ },
+ "./model/schedule/global/jitter/constrained_deadlines.v": {
+ "platform_cpus_busy_with_interfering_tasks": 65,
+ "platform_fp_cpus_busy_with_interfering_tasks": 85
+ },
+ "./model/schedule/global/jitter/platform.v": {
+ "work_conserving_eq_work_conserving_count": 68
+ },
+ "./model/schedule/uni/jitter/busy_interval.v": {
+ "busy_interval_is_bounded": 59,
+ "exists_busy_interval_prefix": 68,
+ "not_quiet_implies_exists_scheduled_hp_job": 46
+ },
+ "./model/schedule/uni/limited/abstract_RTA/abstract_rta.v": {
+ "in": 115
+ },
+ "./model/schedule/uni/limited/abstract_RTA/abstract_seq_rta.v": {
+ "bound_for_cumulative_job_interference_actual": 140,
+ "task_rbf_excl_tsk_bounds_task_workload_excl_j": 69
+ },
+ "./model/schedule/uni/limited/busy_interval.v": {
+ "busy_interval_has_uninterrupted_service": 84,
+ "busy_interval_is_bounded": 81,
+ "exists_busy_interval_prefix": 75,
+ "no_idle_time_within_non_quiet_time_interval": 76,
+ "pending_hp_job_exists": 73
+ },
+ "./model/schedule/uni/limited/edf/nonpr_reg/concrete_models/response_time_bound.v": {
+ "uniprocessor_response_time_bound_edf_with_fixed_preemption_points": 168,
+ "uniprocessor_response_time_bound_edf_with_floating_nonpreemptive_regions": 81
+ },
+ "./model/schedule/uni/limited/edf/nonpr_reg/response_time_bound.v": {
+ "priority_inversion_is_bounded": 56,
+ "priority_inversion_is_bounded_by_blocking": 58
+ },
+ "./model/schedule/uni/limited/edf/response_time_bound.v": {
+ "A_is_in_concrete_search_space": 85,
+ "instantiated_task_interference_is_bounded": 163
+ },
+ "./model/schedule/uni/limited/fixed_priority/nonpr_reg/concrete_models/response_time_bound.v": {
+ "uniprocessor_response_time_bound_fp_with_fixed_preemption_points": 168,
+ "uniprocessor_response_time_bound_fp_with_floating_nonpreemptive_regions": 81
+ },
+ "./model/schedule/uni/limited/fixed_priority/nonpr_reg/response_time_bound.v": {
+ "priority_inversion_is_bounded": 52
+ },
+ "./model/schedule/uni/limited/fixed_priority/response_time_bound.v": {
+ "instantiated_task_interference_is_bounded": 47
+ },
+ "./model/schedule/uni/limited/jlfp_instantiation.v": {
+ "cumulative_task_interference_split": 62,
+ "instantiated_cumulative_interference_of_hep_jobs_equal_total_interference_of_hep_jobs": 114,
+ "instantiated_cumulative_interference_of_hep_tasks_equal_total_interference_of_hep_tasks": 127,
+ "instantiated_quiet_time_equivalent_edf_quiet_time": 102
+ },
+ "./model/schedule/uni/limited/platform/limited.v": {
+ "model_with_fixed_preemption_points_is_model_with_bounded_nonpreemptive_regions": 83
+ },
+ "./model/schedule/uni/limited/platform/priority_inversion_is_bounded.v": {
+ "=>": 119,
+ "not_quiet_implies_exists_scheduled_hp_job_after_preemption_point": 55,
+ "not_quiet_implies_exists_scheduled_hp_job_at_preemption_point": 90,
+ "scheduling_of_any_segment_starts_with_preemption_time": 44
+ },
+ "./model/schedule/uni/limited/platform/util.v": {
+ "belonging_to_segment_of_seq_is_total": 46,
+ "distance_between_neighboring_elements_le_max_distance_in_seq": 43,
+ "domination_of_distances_implies_domination_of_seq": 58,
+ "max_distance_in_nontrivial_seq_is_positive": 127,
+ "max_distance_in_seq_le_last_element_of_seq": 47,
+ "max_of_dominating_seq": 47
+ },
+ "./model/schedule/uni/nonpreemptive/schedule.v": {
+ "j_is_not_scheduled_at_t_minus_service_minus_one": 54,
+ "j_is_scheduled_at_t_minus_service": 74
+ },
+ "./model/schedule/uni/service.v": {
+ "all_jobs_have_completed_impl_workload_eq_service": 44,
+ "incremental_service_during": 70
+ },
+ "./model/schedule/uni/susp/build_suspension_table.v": {
+ "suspension_duration_matches_predicate_up_to_t_max": 95
+ },
+ "./model/schedule/uni/susp/last_execution.v": {
+ "last_execution_idempotent": 41,
+ "same_service_implies_same_last_execution": 49
+ },
+ "./model/schedule/uni/susp/suspension_intervals.v": {
+ "cumulative_suspension_eq_total_suspension": 86,
+ "cumulative_suspension_le_total_suspension": 57
+ },
+ "./model/schedule/uni/sustainability.v": {
+ "weak_sustainability_equivalence": 50
+ },
+ "./util/div_mod.v": {
+ "divSn_cases": 54
+ },
+ "./util/list.v": {
+ "subseq_leq_size": 52
+ },
+ "./util/step_function.v": {
+ "exists_intermediate_point": 43
+ },
+ "./util/sum.v": {
+ "sum_majorant_eqn": 40
+ }
+ }
+}
diff git a/scripts/proofloc.py b/scripts/proofloc.py
new file mode 100755
index 0000000000000000000000000000000000000000..2b0914b7113df5c766606df32b40306a7abfbb1c
 /dev/null
+++ b/scripts/proofloc.py
@@ 0,0 +1,195 @@
+#!/usr/bin/env python3
+
+import argparse
+import re
+import json
+import sys
+
+from collections import defaultdict
+
+SINGLE_LINE_PROOF_PATTERN = re.compile(
+r"""
+[ \t^]Proof\. # Proof keyword
+.* # The actual proof.
+[ \t^.]Qed\. # End of proof keyword.
+"""
+, re.VERBOSE)
+
+PROOF_START_PATTERN = re.compile(r"[ \t^]Proof\.")
+PROOF_END_PATTERN = re.compile(r"[ \t^.]Qed\.")
+
+CLAIM_NAME_PATTERN = re.compile(
+r"""
+# first a keyword indicating a claim
+(LemmaTheoremCorollaryFactRemarkExample)
+\s+ # whitespace
+([^:\s]+) # the identifier (anything up to the first space or colon)
+"""
+, re.VERBOSE)
+
+def banner(fname):
+ fill1 = (76  len(fname)) // 2
+ fill2 = 76  len(fname)  fill1
+ print("%s[ %s ]%s" % ('=' * fill1, fname, '=' * fill2))
+
+def show_line(tag, line_number, line):
+ print("%3s %4d %s" % (tag, line_number + 1, line), end='')
+
+def silent(tag, line_number, line):
+ pass
+
+def process_file(fname, annotate=silent):
+ proofs = []
+ in_proof = False
+ claim = '???'
+ with open(fname) as f:
+ for i, line in enumerate(f):
+ name_match = CLAIM_NAME_PATTERN.search(line)
+ if not name_match is None:
+ claim = name_match.group(2)
+ if in_proof:
+ if PROOF_END_PATTERN.search(line):
+ annotate('###', i, line)
+ proofs.append( (fname, start + 1, claim, i  start  1) )
+ in_proof = False
+ claim = '???'
+ else:
+ annotate(' P ', i, line)
+ elif SINGLE_LINE_PROOF_PATTERN.search(line):
+ annotate('*P*', i, line)
+ proofs.append( (fname, i + 1, claim, 1) )
+ claim = '???'
+ elif PROOF_START_PATTERN.search(line):
+ annotate('***', i, line)
+ in_proof = True
+ start = i
+ else:
+ annotate(' ', i, line)
+
+ return proofs
+
+def show_histogram(opts, all_proofs):
+ limit = 0
+ counts = []
+ for fname, line, claim, length in reversed(all_proofs):
+ if length > limit:
+ limit += opts.bin_size
+ counts.append(0)
+ counts[1] += 1
+ print(" LOC #Proofs")
+ print("=" * 19)
+ for i, count in enumerate(counts):
+ print(" <= %3d %7d" % ((i + 1) * opts.bin_size, count))
+
+def create_db(opts, all_proofs):
+ db = {}
+ db["manual_exceptions"] = opts.long_proofs["manual_exceptions"]
+ db["legacy_proofs"] = defaultdict(dict)
+ for fname, line, claim, length in all_proofs:
+ if fname in db["manual_exceptions"] and \
+ claim in db["manual_exceptions"][fname]:
+ # skip manually approved long proofs
+ continue
+ if length >= opts.threshold:
+ db["legacy_proofs"][fname][claim] = length
+ print(json.dumps(db, sort_keys=True, indent=4))
+
+def check_proof_lengths(opts, all_proofs):
+ new_long_proofs = False
+ known_long_proofs = 0
+ for fname, line, claim, length in all_proofs:
+ if length <= opts.threshold:
+ break
+ known = False
+ for category in ["manual_exceptions", "legacy_proofs"]:
+ if fname in opts.long_proofs[category] and \
+ claim in opts.long_proofs[category][fname] and \
+ opts.long_proofs[category][fname][claim] >= length:
+ # this is a known long proof of nonincreased length
+ # no need to complain
+ known = True
+ if not known:
+ print("Warning: new long proof of %s in %s:%d!"
+ % (claim, fname, line), file=sys.stderr)
+ new_long_proofs = True
+ else:
+ known_long_proofs = known_long_proofs + 1
+ print("Checked %d proofs in %d files, while skipping %d known long proofs."
+ % (len(all_proofs), len(opts.input_files), known_long_proofs))
+ return new_long_proofs
+
+def rank_proofs(opts, all_proofs):
+ print("%12s %s" % ("Proof LOC", "Location (Claim)"))
+ print("=" * 80)
+ for fname, line, claim, length in all_proofs:
+ if (not opts.extract) and length <= opts.threshold:
+ break
+ print("%12d %s:%d (%s)" % (length, fname, line, claim))
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="Proof counting tool")
+
+ parser.add_argument('input_files', nargs='*',
+ metavar='Coqfile',
+ help='input Coq files (*.v)')
+
+ parser.add_argument('t', 'threshold', default=40,
+ action='store', type=int,
+ help='up to which length is a proof is considered ok')
+
+ parser.add_argument('b', 'binsize', default=None,
+ action='store', type=int, metavar="BINSIZE",
+ help='report length histogram with given bin size')
+
+ parser.add_argument('extract', default=False, action='store_true',
+ help='simply list all identified proofs')
+
+ parser.add_argument('annotate', default=False, action='store_true',
+ help='dump the file with proofs marked')
+
+ parser.add_argument('createdb', default=False, action='store_true',
+ help='create a DB of known long proofs (JSON format)')
+
+ parser.add_argument('longproofs', default=None,
+ type=argparse.FileType('r'), metavar="JSONFILE",
+ help='JSON DB of known long proofs')
+
+ parser.add_argument('check', default=False, action='store_true',
+ help='complain and return nonzero exit code if there '
+ 'are new toolong proofs')
+
+ return parser.parse_args()
+
+def main():
+ opts = parse_args()
+
+ if opts.long_proofs:
+ opts.long_proofs = json.load(opts.long_proofs)
+ else:
+ opts.long_proofs = { "manual_exceptions" : {}, "legacy_proofs" : {} }
+
+ all_proofs = []
+ annotate = show_line if opts.annotate else silent
+ for f in opts.input_files:
+ if opts.annotate:
+ banner(f)
+ all_proofs += process_file(f, annotate=annotate)
+ if opts.annotate:
+ print("\n")
+
+ if not opts.extract:
+ all_proofs.sort(key=lambda x: x[3], reverse=True)
+
+ if opts.bin_size:
+ show_histogram(opts, all_proofs)
+ elif opts.create_db:
+ create_db(opts, all_proofs)
+ elif opts.check:
+ sys.exit(check_proof_lengths(opts, all_proofs))
+ else:
+ rank_proofs(opts, all_proofs)
+
+if __name__ == '__main__':
+ main()
+
diff git a/util/all.v b/util/all.v
index 25acc36ba7e9401eb2ac8d5ac29202e57bed0faa..892aad02c146e41dbe06e142bf9ee794f431c6a4 100644
 a/util/all.v
+++ b/util/all.v
@@ 1,6 +1,7 @@
Require Export rt.util.tactics.
Require Export rt.util.notation.
Require Export rt.util.bigcat.
+Require Export rt.util.pick.
Require Export rt.util.bigord.
Require Export rt.util.counting.
Require Export rt.util.div_mod.
@@ 16,4 +17,4 @@ Require Export rt.util.sum.
Require Export rt.util.minmax.
Require Export rt.util.seqset.
Require Export rt.util.step_function.
Require Export rt.util.pick.
\ No newline at end of file
+Require Export rt.util.epsilon.
diff git a/util/epsilon.v b/util/epsilon.v
new file mode 100644
index 0000000000000000000000000000000000000000..d66c6b81f9ca62cb9c4a46f54a6657b845572648
 /dev/null
+++ b/util/epsilon.v
@@ 0,0 +1,6 @@
+Module Epsilon.
+
+ (* ε is defined as the smallest positive number. *)
+ Definition ε := 1.
+
+End Epsilon.
\ No newline at end of file
diff git a/util/find_seq.v b/util/find_seq.v
index 516dfe17b82398efbcf2695f4b7f3db0edfd831e..440607f249f3d4eabb1daa4468f0974011aec697 100644
 a/util/find_seq.v
+++ b/util/find_seq.v
@@ 51,9 +51,11 @@ Section find_seq.
Proof.
intros.
apply /negP /negP /hasPn.
 intros. apply find_uniql with (x:=x) in H;auto.
 case (x0==x)eqn:XX;move/eqP in XX;last trivial.
 rewrite XX in H0. by subst.
+ unfold prop_in1. intros.
+ apply find_uniql with (x:=x) in H; last by assumption.
+ case (x0==x) eqn:XX; last trivial.
+ move/eqP in XX.
+ rewrite XX in H1; by contradiction.
Qed.
Lemma findP_in_seq:
diff git a/util/list.v b/util/list.v
index 8e441bb828a2d6e692bd045674a6dbf102414a02..e822d2314b2c06a72a305aa57cdec916249ec24b 100644
 a/util/list.v
+++ b/util/list.v
@@ 94,9 +94,67 @@ Section UniqList.
}
by apply filter_idx_lt_take.
Qed.
+
+ Lemma mapP2 (T: Type) (T': eqType) (s: seq T) (f: T > T') y:
+ reflect (exists2 x, List.In x s & y = f x) (y \in map f s).
+ Proof.
+ elim: s => [x s IHs]; first by right; case.
+ rewrite /= in_cons eq_sym; case Hxy: (f x == y);
+ first by left; exists x; [by left  by rewrite (eqP Hxy)].
+ apply: (iffP IHs) => [[x' Hx' >][x' Hx' Dy]];
+ first by exists x'; [by right  by done].
+ exists x'; last by done.
+ by subst y; move: Hx' => [EQ  IN] //; subst; rewrite eq_refl in Hxy.
+ Qed.
End UniqList.
+(* Additional lemmas about rem for lists. *)
+Section RemList.
+
+ (* We prove that if x lies in xs excluding y, then x also lies in xs. *)
+ Lemma rem_in:
+ forall (T: eqType) (x y: T) (xs: seq T),
+ x \in rem y xs > x \in xs.
+ Proof.
+ clear; intros.
+ induction xs; simpl in H.
+ { by rewrite in_nil in H. }
+ { rewrite in_cons; apply/orP.
+ destruct (a == y) eqn:EQ.
+ { by move: EQ => /eqP EQ; subst a; right. }
+ { move: H; rewrite in_cons; move => /orP [/eqP H  H].
+  by subst a; left.
+  by right; apply IHxs.
+ }
+ }
+ Qed.
+
+ (* We prove that if we remove an element x for which P x from
+ a filter, then the size of the filter decreases by 1. *)
+ Lemma filter_size_rem:
+ forall (T: eqType) (x:T) (xs: seq T) (P: T > bool),
+ (x \in xs) >
+ P x >
+ size [seq y < xs  P y] = size [seq y < rem x xs  P y] + 1.
+ Proof.
+ clear; intros.
+ induction xs; first by inversion H.
+ move: H; rewrite in_cons; move => /orP [/eqP H  H]; subst.
+ { by simpl; rewrite H0 [X in X = _]addn1 eq_refl. }
+ { specialize (IHxs H); simpl in *.
+ case EQab: (a == x); simpl.
+ { move: EQab => /eqP EQab; subst.
+ by rewrite H0 addn1. }
+ { case Pa: (P a); simpl.
+  by rewrite IHxs !addn1.
+  by rewrite IHxs.
+ }
+ }
+ Qed.
+
+End RemList.
+
(* Additional lemmas about list zip. *)
Section Zip.
@@ 685,4 +743,89 @@ Section Order.
rel x2 x1 >
x1 = x2.
End Order.
\ No newline at end of file
+End Order.
+
+(* In this section we prove some additional lemmas about sequences. *)
+Section AdditionalLemmas.
+
+ (* We define a local function max over lists using foldl and maxn. *)
+ Let max := foldl maxn 0.
+
+ (* We prove that max {x, xs} is equal to max {x, max xs}. *)
+ Lemma seq_max_cons: forall x xs, max (x :: xs) = maxn x (max xs).
+ Proof.
+ have L: forall s x xs, foldl maxn s (x::xs) = maxn x (foldl maxn s xs).
+ { clear; intros.
+ generalize dependent s; generalize dependent x.
+ induction xs.
+ { by intros; rewrite maxnC. }
+ { intros; simpl in *.
+ by rewrite maxnC IHxs [maxn s a]maxnC IHxs maxnA [maxn s x]maxnC.
+ }
+ }
+ by intros; unfold max; apply L.
+ Qed.
+
+ (* We prove that for any two sequences xs and ys the fact that xs is a subsequence
+ of ys implies that the size of xs is at most the size of ys. *)
+ Lemma subseq_leq_size:
+ forall {T: eqType} (xs ys: seq T),
+ uniq xs >
+ (forall x, x \in xs > x \in ys) >
+ size xs <= size ys.
+ Proof.
+ clear; intros ? ? ? UNIQ SUB.
+ have Lem:
+ forall a ys,
+ (a \in ys) >
+ exists ysl ysr, ys = ysl ++ [::a] ++ ysr.
+ { clear; intros ? ? ? SUB.
+ induction ys; first by done.
+ move: SUB; rewrite in_cons; move => /orP [/eqP EQIN].
+  by subst; exists [::], ys.
+  feed IHys; first by done.
+ clear IN; move: IHys => [ysl [ysr EQ]].
+ by subst; exists(a0::ysl), ysr.
+ }
+ have EXm: exists m, size ys <= m.
+ { by exists (size ys). }
+ move: EXm => [m SIZEm].
+ move: SIZEm UNIQ SUB; move: xs ys.
+ induction m.
+ { intros.
+ move: SIZEm; rewrite leqn0 size_eq0; move => /eqP SIZEm; subst ys.
+ destruct xs; first by done.
+ specialize (SUB s).
+ feed SUB; first by rewrite in_cons; apply/orP; left.
+ by done.
+ }
+ { intros.
+ destruct xs as [  x xs]; first by done.
+ specialize (@Lem _ x ys).
+ feed Lem.
+ { by apply SUB; rewrite in_cons; apply/orP; left. }
+ move: Lem => [ysl [ysr EQ]]; subst ys.
+ rewrite !size_cat; simpl; rewrite addnC add1n addSn ltnS size_cat.
+ eapply IHm.
+  move: SIZEm; rewrite !size_cat; simpl; move => SIZE.
+ by rewrite add1n addnS ltnS addnC in SIZE.
+  by move: UNIQ; rewrite cons_uniq; move => /andP [_ UNIQ].
+  intros a IN.
+ destruct (a == x) eqn: EQ.
+ { exfalso.
+ move: EQ UNIQ; rewrite cons_uniq; move => /eqP EQ /andP [NIN UNIQ].
+ by subst; move: NIN => /negP NIN; apply: NIN.
+ }
+ { specialize (SUB a).
+ feed SUB.
+ { by rewrite in_cons; apply/orP; right. }
+ clear IN; move: SUB; rewrite !mem_cat; move => /orP [IN /orP [ININ]].
+  by apply/orP; right.
+  exfalso.
+ by move: IN; rewrite in_cons; move => /orP [ININ]; [rewrite IN in EQ  ].
+  by apply/orP; left.
+ }
+ }
+ Qed.
+
+End AdditionalLemmas.
\ No newline at end of file
diff git a/util/minmax.v b/util/minmax.v
index ea69b93b3841ada7e6cfd4403d812a8e42ce09b2..5d8e673eead69db683195e482c4d06ccf26d50a8 100644
 a/util/minmax.v
+++ b/util/minmax.v
@@ 514,14 +514,55 @@ End MinMaxSeq.
(* Additional lemmas about max. *)
Section ExtraLemmas.

 Lemma leq_big_max I r (P : pred I) (E1 E2 : I > nat) :
 (forall i, P i > E1 i <= E2 i) >
 \max_(i < r  P i) E1 i <= \max_(i < r  P i) E2 i.
+
+ 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.
 move => leE12; elim/big_ind2 : _ => // m1 m2 n1 n2.
 intros LE1 LE2; rewrite leq_max; unfold maxn.
 by destruct (m2 < n2) eqn:LT; [by apply/orP; right  by apply/orP; left].
+ 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 :
diff git a/util/nat.v b/util/nat.v
index 8cb1de9b36c62cb77ede8e206205e88e6b43d772..7cca339ef50b20361f3c5be1cbd8f6178de1b915 100644
 a/util/nat.v
+++ b/util/nat.v
@@ 22,15 +22,18 @@ Section NatLemmas.
n1 >= n2 >
(m1 + n1)  (m2 + n2) = m1  m2 + (n1  n2).
Proof. by ins; ssromega. Qed.

 Lemma subh3 :
+
+ Lemma subh3:
forall m n p,
m + p <= n >
 n >= p >
m <= n  p.
Proof.
 ins. rewrite < leq_add2r with (p := p).
 by rewrite subh1 // addnBA // subnn addn0.
+ clear.
+ intros.
+ rewrite < leq_add2r with (p := p).
+ rewrite subh1 //.
+  by rewrite addnBA // subnn addn0.
+  by apply leq_trans with (m+p); first rewrite leq_addl.
Qed.
Lemma subh4:
diff git a/util/pick.v b/util/pick.v
index 3cc3a0929681483d452087a3b431809df3c7c141..dea4dcce3b4e945ee0faaf136e4f45fe8a166751 100644
 a/util/pick.v
+++ b/util/pick.v
@@ 11,17 +11,18 @@ Definition arg_pred_nat n (P: pred 'I_n) ord :=
Definition pred_min_nat n (P: pred 'I_n) := arg_pred_nat n P leq.
Definition pred_max_nat n (P: pred 'I_n) := arg_pred_nat n P (fun x y => geq x y).
+Definition to_pred_ord n (P: pred nat) := (fun x:'I_n => P (nat_of_ord x)).
(** Defining Pick functions *)
(* (pick_any n P) returns some number < n that satisfies P, or 0 if it cannot be found. *)
Definition pick_any n (P: pred 'I_n) := default0 (pick P).
+Definition pick_any n (P: pred nat) := default0 (pick (to_pred_ord n P)).
(* (pick_min n P) returns the smallest number < n that satisfies P, or 0 if it cannot be found. *)
Definition pick_min n (P: pred 'I_n) := default0 (pick (pred_min_nat n P)).
+Definition pick_min n (P: pred nat) := default0 (pick (pred_min_nat n (to_pred_ord n P))).
(* (pick_max n P) returns the largest number < n that satisfies P, or 0 if it cannot be found. *)
Definition pick_max n (P: pred 'I_n) := default0 (pick (pred_max_nat n P)).
+Definition pick_max n (P: pred nat) := default0 (pick (pred_max_nat n (to_pred_ord n P))).
(** Improved notation *)
@@ 30,27 +31,27 @@ Definition pick_max n (P: pred 'I_n) := default0 (pick (pred_max_nat n P)).
[pickmin x <= N  P], [pickmin x < N  P]
[pickmax x <= N  P], [pickmax x < N  P]. *)
Notation "[ 'pickany' x <= N  P ]" :=
 (pick_any N.+1 (fun x : 'I_N.+1 => P%B))
+ (pick_any N.+1 (fun x : nat => P%B))
(at level 0, x ident, only parsing) : form_scope.
Notation "[ 'pickany' x < N  P ]" :=
 (pick_any N (fun x : 'I_N => P%B))
+ (pick_any N (fun x : nat => P%B))
(at level 0, x ident, only parsing) : form_scope.
Notation "[ 'pickmin' x <= N  P ]" :=
 (pick_min N.+1 (fun x : 'I_N.+1 => P%B))
+ (pick_min N.+1 (fun x : nat => P%B))
(at level 0, x ident, only parsing) : form_scope.
Notation "[ 'pickmin' x < N  P ]" :=
 (pick_min N (fun x : 'I_N => P%B))
+ (pick_min N (fun x : nat => P%B))
(at level 0, x ident, only parsing) : form_scope.
Notation "[ 'pickmax' x <= N  P ]" :=
 (pick_max N.+1 (fun x : 'I_N.+1 => P%B))
+ (pick_max N.+1 (fun x : nat => P%B))
(at level 0, x ident, only parsing) : form_scope.
Notation "[ 'pickmax' x < N  P ]" :=
 (pick_max N (fun x : 'I_N => P%B))
+ (pick_max N (fun x : nat => P%B))
(at level 0, x ident, only parsing) : form_scope.
(** Lemmas about pick_any *)
@@ 58,11 +59,11 @@ Notation "[ 'pickmax' x < N  P ]" :=
Section PickAny.
Variable n: nat.
 Variable p: pred 'I_n.
+ Variable p: pred nat.
Variable P: nat > Prop.
 Hypothesis EX: exists x:'I_n, p x.
+ Hypothesis EX: exists x, x < n /\ p x.
Hypothesis HOLDS: forall x, p x > P x.
@@ 73,8 +74,8 @@ Section PickAny.
rewrite /pick_any /default0.
case: pickP; first by intros x PRED; apply HOLDS.
intros NONE; red in NONE; exfalso.
 move: EX => [x PRED].
 by specialize (NONE x); rewrite PRED in NONE.
+ move: EX => [x [LTN PRED]].
+ by specialize (NONE (Ordinal LTN)); rewrite /to_pred_ord /= PRED in NONE.
Qed.
End PickAny.
@@ 83,12 +84,12 @@ End PickAny.
Section PickMin.
Variable n: nat.
 Variable p: pred 'I_n.
+ Variable p: pred nat.
Variable P: nat > Prop.
(* Assume that there is some number < n that satisfies p. *)
 Hypothesis EX: exists x:'I_n, p x.
+ Hypothesis EX: exists x, x < n /\ p x.
Section Bound.
@@ 99,12 +100,12 @@ Section PickMin.
case: pickP.
{
move => x /andP [PRED /forallP ALL].
 by rewrite /default0.
+ by rewrite /default0.
}
{
intros NONE; red in NONE; exfalso.
 move: EX => [x PRED]; clear EX.
 set argmin := arg_min x p id.
+ move: EX => [x [LT PRED]]; clear EX.
+ set argmin := arg_min (Ordinal LT) p id.
specialize (NONE argmin).
suff ARGMIN: (pred_min_nat n p) argmin by rewrite ARGMIN in NONE.
rewrite /argmin; case: arg_minP; first by done.
@@ 120,9 +121,9 @@ Section PickMin.
Hypothesis MIN:
forall x,
 p x >
x < n >
 (forall y, p y > x <= y) >
+ p x >
+ (forall y, y < n > p y > x <= y) >
P x.
(* Next, we show that any property P of (pick_min n p) can be proven by showing
@@ 133,70 +134,71 @@ Section PickMin.
case: pickP.
{
move => x /andP [PRED /forallP ALL].
 apply MIN; try (by done).
 by intros y Py; specialize (ALL y); move: ALL => /implyP ALL; apply ALL.
+ apply MIN; [by rewrite /default0  by done ].
+ intros y LTy Py; specialize (ALL (Ordinal LTy)).
+ by move: ALL => /implyP ALL; apply ALL.
}
{
intros NONE; red in NONE; exfalso.
 move: EX => [x PRED]; clear EX.
 set argmin := arg_min x p id.
+ move: EX => [x [LT PRED]]; clear EX.
+ set argmin := arg_min (Ordinal LT) p id.
specialize (NONE argmin).
suff ARGMIN: (pred_min_nat n p) argmin by rewrite ARGMIN in NONE.
rewrite /argmin; case: arg_minP; first by done.
intros y Py MINy.
apply/andP; split; first by done.
 by apply/forallP; intros y0; apply/implyP; intros Py0; apply MINy.
+ by apply/forallP; intros y0; apply/implyP; intros Py0; apply MINy.
}
Qed.
End Minimum.

+
End PickMin.
(** Lemmas about pick_max *)
Section PickMax.
Variable n: nat.
 Variable p: pred 'I_n.
+ Variable p: pred nat.
Variable P: nat > Prop.
(* Assume that there is some number < n that satisfies p. *)
 Hypothesis EX: exists x:'I_n, p x.
+ Hypothesis EX: exists x, x < n /\ p x.
Section Bound.
 (* First, we show that (pick_max n p) < n. *)
+ (* First, we show that (pick_max n p) < n... *)
Lemma pick_max_ltn: pick_max n p < n.
Proof.
rewrite /pick_max /odflt /oapp.
case: pickP.
{
move => x /andP [PRED /forallP ALL].
 by rewrite /default0.
+ by rewrite /default0.
}
{
intros NONE; red in NONE; exfalso.
 move: EX => [x PRED]; clear EX.
 set argmax := arg_max x p id.
+ move: EX => [x [LT PRED]]; clear EX.
+ set argmax := arg_max (Ordinal LT) p id.
specialize (NONE argmax).
suff ARGMAX: (pred_max_nat n p) argmax by rewrite ARGMAX in NONE.
rewrite /argmax; case: arg_maxP; first by done.
intros y Py MAXy.
apply/andP; split; first by done.
 by apply/forallP; intros y0; apply/implyP; intros Py0; apply MAXy.
+ by apply/forallP; intros y0; apply/implyP; intros Py0; apply MAXy.
}
Qed.
End Bound.

+
Section Maximum.
Hypothesis MAX:
forall x,
 p x >
x < n >
 (forall y, p y > x >= y) >
+ p x >
+ (forall y, y < n > p y > x >= y) >
P x.
(* Next, we show that any property P of (pick_max n p) can be proven by showing that
@@ 207,22 +209,83 @@ Section PickMax.
case: pickP.
{
move => x /andP [PRED /forallP ALL].
 apply MAX; try (by done).
 by intros y Py; specialize (ALL y); move: ALL => /implyP ALL; apply ALL.
+ apply MAX; [by rewrite /default0  by rewrite /default0 ].
+ intros y LTy Py; specialize (ALL (Ordinal LTy)).
+ by move: ALL => /implyP ALL; apply ALL.
}
{
intros NONE; red in NONE; exfalso.
 move: EX => [x PRED]; clear EX.
 set argmax := arg_max x p id.
+ move: EX => [x [LT PRED]]; clear EX.
+ set argmax := arg_max (Ordinal LT) p id.
specialize (NONE argmax).
suff ARGMAX: (pred_max_nat n p) argmax by rewrite ARGMAX in NONE.
rewrite /argmax; case: arg_maxP; first by done.
intros y Py MAXy.
apply/andP; split; first by done.
 by apply/forallP; intros y0; apply/implyP; intros Py0; apply MAXy.
+ by apply/forallP; intros y0; apply/implyP; intros Py0; apply MAXy.
}
Qed.
End Maximum.
+
+End PickMax.
+
+Section Predicate.
+
+ Variable n: nat.
+ Variable p: pred nat.
+
+ Hypothesis EX: exists x, x < n /\ p x.
+
+ (* Here we prove that pick_any satiesfies the predicate p, ... *)
+ Lemma pick_any_pred: p (pick_any n p).
+ Proof.
+ by apply pick_any_holds.
+ Qed.
+
+ (* ...and the same holds for pick_min... *)
+ Lemma pick_min_pred: p (pick_min n p).
+ Proof.
+ by apply pick_min_holds.
+ Qed.
+
+ (* ...and pick_max. *)
+ Lemma pick_max_pred: p (pick_max n p).
+ Proof.
+ by apply pick_max_holds.
+ Qed.
+
+End Predicate.
+
+Section PickMinCompare.
+
+ Variable n: nat.
+ Variable p1 p2: pred nat.
+
+ Hypothesis EX1 : exists x, x < n /\ p1 x.
+ Hypothesis EX2 : exists x, x < n /\ p2 x.
+
+ Hypothesis OUT:
+ forall x y, x < n > y < n > p1 x > p2 y > ~~ p1 y > x <= y.
+
+ Lemma pick_min_compare: pick_min n p1 <= pick_min n p2.
+ Proof.
+ set m1:= pick_min _ _.
+ set m2:= pick_min _ _.
+ case IN: (p1 m2).
+ {
+ apply pick_min_holds; first by done.
+ intros x Px LTN ALL.
+ by apply ALL; first by apply pick_min_ltn.
+ }
+ {
+ apply (OUT m1 m2).
+  by apply pick_min_ltn.
+  by apply pick_min_ltn.
+  by apply pick_min_pred.
+  by apply pick_min_pred.
+  by apply negbT.
+ }
+ Qed.
End PickMax.
\ No newline at end of file
+End PickMinCompare.
\ No newline at end of file
diff git a/util/sorting.v b/util/sorting.v
index ae0bbcecbaa81f8f7cd46d7601e7d3be246aaec4..3fb7d5f0498e6d1c48758a8664af10fc1f702fbe 100644
 a/util/sorting.v
+++ b/util/sorting.v
@@ 1,123 +1,161 @@
Require Import rt.util.tactics rt.util.induction rt.util.list.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop path.
(* Lemmas about sorted lists. *)
+(** * Sorting *)
+(** In this modeule we prove a few lemmas about sorted sequences. *)
Section Sorting.

 Lemma prev_le_next :
 forall (T: Type) (F: T>nat) r (x0: T) i k,
 (forall i, i < (size r).1 > F (nth x0 r i) <= F (nth x0 r i.+1)) >
 (i + k <= (size r).1) >
 F (nth x0 r i) <= F (nth x0 r (i+k)).
 Proof.
 intros T F r x0 i k ALL SIZE.
 generalize dependent i. generalize dependent k.
 induction k; intros; first by rewrite addn0 leqnn.
 specialize (IHk i.+1); exploit IHk; [by rewrite addSnnS  intro LE].
 apply leq_trans with (n := F (nth x0 r (i.+1)));
 last by rewrite addSnnS.
 apply ALL, leq_trans with (n := i + k.+1); last by ins.
 by rewrite addnS ltnS leq_addr.
 Qed.
 Lemma sort_ordered:
 forall {T: eqType} (leT: rel T) (s: seq T) x0 idx,
 sorted leT s >
 idx < (size s).1 >
 leT (nth x0 s idx) (nth x0 s idx.+1).
 Proof.
 intros T leT s x0 idx SORT LT.
 induction s; first by rewrite /= ltn0 in LT.
 simpl in SORT, LT; move: SORT => /pathP SORT.
 by simpl; apply SORT.
 Qed.

 Lemma sorted_rcons_prefix :
 forall {T: eqType} (leT: rel T) s x,
 sorted leT (rcons s x) >
 sorted leT s.
 Proof.
 intros T leT s x SORT; destruct s; simpl; first by ins.
 rewrite rcons_cons /= rcons_path in SORT.
 by move: SORT => /andP [PATH _].
 Qed.
+ Section SortedImplLeIdx.
+
+ (* Consider an arbitrary type T... *)
+ Variable T: eqType.
 Lemma order_sorted_rcons :
 forall {T: eqType} (leT: rel T) (s: seq T) (x last: T),
 transitive leT >
 sorted leT (rcons s last) >
 x \in s >
 leT x last.
 Proof.
 intros T leT s x last TRANS SORT IN.
 induction s; first by rewrite in_nil in IN.
 simpl in SORT; move: IN; rewrite in_cons; move => /orP IN.
 destruct IN as [HEAD  TAIL];
 last by apply IHs; [by apply path_sorted in SORT by ins].
 move: HEAD => /eqP HEAD; subst a.
 apply order_path_min in SORT; last by ins.
 move: SORT => /allP SORT.
 by apply SORT; rewrite mem_rcons in_cons; apply/orP; left.
 Qed.

 Lemma sorted_lt_idx_implies_rel :
 forall {T: eqType} (leT: rel T) (s: seq T) x0 i1 i2,
 transitive leT >
 sorted leT s >
 i1 < i2 >
 i2 < size s >
 leT (nth x0 s i1) (nth x0 s i2).
 Proof.
 intros T leT s x0 i1 i2 TRANS SORT LE LEsize.
 generalize dependent i2; rewrite leq_as_delta.
 intros delta LT.
 destruct s; first by rewrite ltn0 in LT.
 simpl in SORT.
 induction delta;
 first by rewrite /= addn0 ltnS in LT; rewrite /= addnE addn0; apply/pathP.
 {
 rewrite /transitive (TRANS (nth x0 (s :: s0) (i1.+1 + delta))) //;
 first by apply IHdelta, leq_ltn_trans with (n := i1.+1 + delta.+1); [rewrite leq_add2l].
 rewrite [delta.+1]addn1 addnA addn1.
 move: SORT => /pathP SORT; apply SORT.
 by rewrite /= [delta.+1]addn1 addnA addn1 ltnS in LT.
 }
 Qed.
+ (* ... and some binary relation leT (≺) on it. *)
+ Variable leT: rel T.
+ Notation "x ≺ y" := (leT x y) (at level 30).
+ Let sorted xs := sorted leT xs.
+
+ (* Next, let xs be a sequence of elements of type T. *)
+ Variable xs: seq T.
+
+ (* Since Coq requires all functions to be total, we
+ need to specify a default value for cases when
+ an index exceeds the size of the sequence. *)
+ Variable default: T.
+ Let nth := nth default.
 Lemma sorted_rel_implies_le_idx :
 forall {T: eqType} (leT: rel T) (s: seq T) x0 i1 i2,
 uniq s >
 antisymmetric_over_list leT s >
 transitive leT >
 sorted leT s >
 leT (nth x0 s i1) (nth x0 s i2) >
 i1 < size s >
 i2 < size s >
 i1 <= i2.
 Proof.
 intros T leT s x0 i1 i2 UNIQ ANTI TRANS SORT REL SIZE1 SIZE2.
 generalize dependent i2.
 induction i1; first by done.
 {
 intros i2 REL SIZE2.
 feed IHi1; first by apply ltn_trans with (n := i1.+1).
 apply leq_trans with (n := i1.+1); first by done.
 rewrite ltn_neqAle; apply/andP; split.
+ (* Next, let's introduce a notation for the nth element of a sequence. *)
+ Notation "xs [ n ]" := (nth xs n) (at level 10).
+
+ (* We prove that, given the fact that sequence xs is sorted,
+ the i'th element of xs is ≺ than the i+1'th element. *)
+ Lemma sort_ordered:
+ forall (idx: nat),
+ sorted xs >
+ idx < (size xs).1 >
+ xs[idx] ≺ xs[idx.+1].
+ Proof.
+ intros idx SORT LT.
+ induction xs; first by rewrite /= ltn0 in LT.
+ simpl in SORT, LT; move: SORT => /pathP SORT.
+ by simpl; apply SORT.
+ Qed.
+
+ (* Next we prove that the prefix of a sorted sequence is also sorted. *)
+ Lemma sorted_rcons_prefix:
+ forall x,
+ sorted (rcons xs x) >
+ sorted xs.
+ Proof.
+ intros x SORT; destruct xs; simpl; first by ins.
+ rewrite rcons_cons /= rcons_path in SORT.
+ by move: SORT => /andP [PATH _].
+ Qed.
+
+ (* Let's assume that relation leT (≺) is transitive. *)
+ Hypothesis H_leT_is_transitive: transitive leT.
+
+ (* Given the fact that sequence xs is sorted, we prove that
+ the last elements of the sequence is the max. element. *)
+ Lemma order_sorted_rcons:
+ forall (x lst: T),
+ sorted (rcons xs lst) >
+ x \in xs >
+ x ≺ lst.
+ Proof.
+ intros x last SORT IN.
+ induction xs as [  a xs']; [  clear xs; rename xs' into xs]; first by rewrite in_nil in IN.
+ simpl in SORT; move: IN; rewrite in_cons; move => /orP IN.
+ destruct IN as [HEAD  TAIL];
+ last by apply IHxs'; [by apply path_sorted in SORT by ins].
+ move: HEAD => /eqP HEAD; subst a.
+ apply order_path_min in SORT; last by ins.
+ move: SORT => /allP SORT.
+ by apply SORT; rewrite mem_rcons in_cons; apply/orP; left.
+ Qed.
+
+ (* Next, we prove that for sorted sequence xs and for any
+ two indices i1 and i2, i1 < i2 implies xs[i1] ≺ xs[i2]. *)
+ Lemma sorted_lt_idx_implies_rel:
+ forall i1 i2,
+ sorted xs >
+ i1 < i2 >
+ i2 < size xs >
+ xs[i1] ≺ xs [i2].
+ Proof.
+ intros i1 i2 SORT LE LEsize.
+ generalize dependent i2; rewrite leq_as_delta.
+ intros delta LT.
+ destruct xs as [  a xs']; [  clear xs; rename xs' into xs]; first by rewrite ltn0 in LT.
+ simpl in SORT.
+ induction delta;
+ first by rewrite /= addn0 ltnS in LT; rewrite /= addnE addn0; apply/pathP.
{
 apply/eqP; red; intro BUG; subst.
 assert (REL': leT (nth x0 s i2) (nth x0 s i2.+1)).
 by apply sorted_lt_idx_implies_rel; rewrite // ltnSn.
 rewrite /antisymmetric_over_list in ANTI.
 exploit (ANTI (nth x0 s i2) (nth x0 s i2.+1)); rewrite ?mem_nth //.
 move => /eqP EQ; rewrite nth_uniq in EQ; try (by done).
 by rewrite [_ == _]negbK in EQ; move: EQ => /negP EQ; apply EQ; apply/eqP.
+ rewrite /transitive (H_leT_is_transitive (nth (a :: xs) (i1.+1 + delta))) //;
+ first by apply IHdelta, leq_ltn_trans with (n := i1.+1 + delta.+1); [rewrite leq_add2l ].
+ rewrite [delta.+1]addn1 addnA addn1.
+ move: SORT => /pathP SORT; apply SORT.
+ by rewrite /= [delta.+1]addn1 addnA addn1 ltnS in LT.
}
+ Qed.
+
+ (* Finally, assuming that (1) xs is sorted and contains
+ no duplicates, (2) ≺ is antisymmetric and transitive,
+ we prove that x[i1] ≺ x[i2] implies i1 ≤ i2. *)
+ Lemma sorted_rel_implies_le_idx:
+ forall i1 i2,
+ uniq xs >
+ antisymmetric_over_list leT xs >
+ sorted xs >
+ xs[i1] ≺ xs[i2] >
+ i1 < size xs >
+ i2 < size xs >
+ i1 <= i2.
+ Proof.
+ intros i1 i2 UNIQ ANTI SORT REL SIZE1 SIZE2.
+ generalize dependent i2.
+ induction i1; first by done.
{
 apply IHi1; last by done.
 rewrite /transitive (TRANS (nth x0 s i1.+1)) //.
 by apply sorted_lt_idx_implies_rel; try (by done); apply ltnSn.
+ intros i2 REL SIZE2.
+ feed IHi1; first by apply ltn_trans with (n := i1.+1).
+ apply leq_trans with (n := i1.+1); first by done.
+ rewrite ltn_neqAle; apply/andP; split.
+ {
+ apply/eqP; red; intro BUG; subst.
+ assert (REL': leT (nth xs i2) (nth xs i2.+1)).
+ by apply sorted_lt_idx_implies_rel; rewrite // ltnSn.
+ rewrite /antisymmetric_over_list in ANTI.
+ exploit (ANTI (nth xs i2) (nth xs i2.+1)); rewrite ?mem_nth //.
+ move => /eqP EQ; rewrite nth_uniq in EQ; try (by done).
+ by rewrite [_ == _]negbK in EQ; move: EQ => /negP EQ; apply EQ; apply/eqP.
+ }
+ {
+ apply IHi1; last by done.
+ rewrite /transitive (H_leT_is_transitive (nth xs i1.+1)) //.
+ by apply sorted_lt_idx_implies_rel; try (by done); apply ltnSn.
+ }
}
 }
 Qed.
+ Qed.
+
+ End SortedImplLeIdx.
+ (* Let F be a function from some type to natural numbers. Then for a
+ sequence xs, the fact that [∀ i: F(xs[i]) ≤ F(xs[i+1])] implies that
+ [forall i k: F(xs[i]) ≤ F(xs[i + k])]. *)
+ Lemma prev_le_next:
+ forall {T: Type} (F: T > nat) (xs: seq T) (def: T) (i k: nat),
+ (forall i, i < (size xs).1 > F (nth def xs i) <= F (nth def xs i.+1)) >
+ (i + k <= (size xs).1) >
+ F (nth def xs i) <= F (nth def xs (i+k)).
+ Proof.
+ intros T F r x i k ALL SIZE.
+ generalize dependent i. generalize dependent k.
+ induction k; intros; first by rewrite addn0 leqnn.
+ specialize (IHk i.+1); exploit IHk; [by rewrite addSnnS  intro LE].
+ apply leq_trans with (n := F (nth x r (i.+1)));
+ last by rewrite addSnnS.
+ apply ALL, leq_trans with (n := i + k.+1); last by ins.
+ by rewrite addnS ltnS leq_addr.
+ Qed.
+
End Sorting.
\ No newline at end of file
diff git a/util/step_function.v b/util/step_function.v
index a1e3fcd4497bb36ab2a33d48f7c10cf49cfa6ab9..c999715f6417b7e1760892424284d0b23d341f42 100644
 a/util/step_function.v
+++ b/util/step_function.v
@@ 85,5 +85,50 @@ Section StepFunction.
End ExistsIntermediateValue.
End Lemmas.
+
+ (* In this section, we prove an analogue of the intermediate
+ value theorem, but for predicates of natural numbers. *)
+ Section ExistsIntermediateValuePredicates.
+
+ (* Let P be any predicate on natural numbers. *)
+ Variable P: nat > bool.
+
+ (* Consider a time interval [t1,t2] such that ... *)
+ Variables t1 t2: nat.
+ Hypothesis H_t1_le_t2: t1 <= t2.
+
+ (* ... P doesn't hold for t1 ... *)
+ Hypothesis H_not_P_at_t1: ~~ P t1.
+
+ (* ... but holds for t2. *)
+ Hypothesis H_P_at_t2: P t2.
+
+ (* Then we prove that within time interval [t1,t2] there exists time
+ instant t such that t is the first time instant when P holds. *)
+ Lemma exists_first_intermediate_point:
+ exists t, (t1 < t <= t2) /\ (forall x, t1 <= x < t > ~~ P x) /\ P t.
+ Proof.
+ have EX: exists x, P x && (t1 < x <= t2).
+ { exists t2.
+ apply/andP; split; first by done.
+ apply/andP; split; last by done.
+ move: H_t1_le_t2; rewrite leq_eqVlt; move => /orP [/eqP EQ  NEQ1]; last by done.
+ by exfalso; subst t2; move: H_not_P_at_t1 => /negP NPt1.
+ }
+ have MIN := ex_minnP EX.
+ move: MIN => [x /andP [Px /andP [LT1 LT2]] MIN]; clear EX.
+ exists x; repeat split; [ apply/andP; split   ]; try done.
+ move => y /andP [NEQ1 NEQ2]; apply/negPn; intros Py.
+ feed (MIN y).
+ { apply/andP; split; first by done.
+ apply/andP; split.
+  move: NEQ1. rewrite leq_eqVlt; move => /orP [/eqP EQ  NEQ1]; last by done.
+ by exfalso; subst y; move: H_not_P_at_t1 => /negP NPt1.
+  by apply ltnW, leq_trans with x.
+ }
+ by move: NEQ2; rewrite ltnNge; move => /negP NEQ2.
+ Qed.
+
+ End ExistsIntermediateValuePredicates.
End StepFunction.
\ No newline at end of file
diff git a/util/sum.v b/util/sum.v
index 7980bd4c2b6fa3153400e05727efd856dc56c38f..5e54b774133861c4e8e28d39e0bac70354f1568f 100644
 a/util/sum.v
+++ b/util/sum.v
@@ 1,88 +1,7 @@
Require Import rt.util.tactics rt.util.notation rt.util.sorting rt.util.nat.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop path.
(* Lemmas about arithmetic with sums. *)
Section SumArithmetic.

 (* Inequality with sums is monotonic with their functions. *)
 Lemma sum_diff_monotonic :
 forall n G F,
 (forall i : nat, i < n > G i <= F i) >
 (\sum_(0 <= i < n) (G i)) <= (\sum_(0 <= i < n) (F i)).
 Proof.
 intros n G F ALL.
 rewrite big_nat_cond [\sum_(0 <= i < n) F i]big_nat_cond.
 apply leq_sum; intros i LT; rewrite andbT in LT.
 move: LT => /andP LT; des.
 by apply ALL, leq_trans with (n := n); ins.
 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.
 induction n; ins; first by rewrite 3?big_geq.
 assert (ALL': forall i, i < n > G i <= F i).
 by ins; apply ALL, leq_trans with (n := n); ins.
 rewrite 3?big_nat_recr // IHn //; simpl.
 rewrite subh1; last by apply sum_diff_monotonic.
 rewrite subh2 //; try apply sum_diff_monotonic; ins.
 rewrite subh1; ins; apply sum_diff_monotonic; ins.
 by apply ALL; rewrite ltnS leqnn.
 Qed.

 Lemma telescoping_sum :
 forall (T: Type) (F: T>nat) r (x0: T),
 (forall i, i < (size r).1 > F (nth x0 r i) <= F (nth x0 r i.+1)) >
 F (nth x0 r (size r).1)  F (nth x0 r 0) =
 \sum_(0 <= i < (size r).1) (F (nth x0 r (i.+1))  F (nth x0 r i)).
 Proof.
 intros T F r x0 ALL.
 have ADD1 := big_add1.
 have RECL := big_nat_recl.
 specialize (ADD1 nat 0 addn 0 (size r) (fun x => true) (fun i => F (nth x0 r i))).
 specialize (RECL nat 0 addn (size r).1 0 (fun i => F (nth x0 r i))).
 rewrite sum_diff; last by ins.
 rewrite addmovr; last by rewrite [_.1]add0n; apply prev_le_next; try rewrite add0n leqnn.
 rewrite subh1; last by apply sum_diff_monotonic.
 rewrite addnC RECL //.
 rewrite addmovl; last by rewrite big_nat_recr // {1}[\sum_(_ <= _ < _) _]addn0; apply leq_add.
 by rewrite addnC big_nat_recr.
 Qed.

 Lemma leq_sum_sub_uniq :
 forall (T: eqType) (r1 r2: seq T) F,
 uniq r1 >
 {subset r1 <= r2} >
 \sum_(i < r1) F i <= \sum_(i < r2) F i.
 Proof.
 intros T r1 r2 F UNIQ SUB; generalize dependent r2.
 induction r1 as [ x r1' IH]; first by ins; rewrite big_nil.
 {
 intros r2 SUB.
 assert (IN: x \in r2).
 by apply SUB; rewrite in_cons eq_refl orTb.
 simpl in UNIQ; move: UNIQ => /andP [NOTIN UNIQ]; specialize (IH UNIQ).
 destruct (splitPr IN).
 rewrite big_cat 2!big_cons /= addnA [_ + F x]addnC addnA leq_add2l.
 rewrite mem_cat in_cons eq_refl in IN.
 rewrite big_cat /=.
 apply IH; red; intros x0 IN0.
 rewrite mem_cat.
 feed (SUB x0); first by rewrite in_cons IN0 orbT.
 rewrite mem_cat in_cons in SUB.
 move: SUB => /orP [SUB1  /orP [/eqP EQx  SUB2]];
 [by rewrite SUB1   by rewrite SUB2 orbT].
 by rewrite EQx IN0 in NOTIN.
 }
 Qed.

End SumArithmetic.

(* Additional lemmas about sum. *)
+(* Lemmas about sum. *)
Section ExtraLemmas.
Lemma extend_sum :
@@ 97,7 +16,7 @@ Section ExtraLemmas.
rewrite > big_cat_nat with (m := t1') (n := t1); try (by done); simpl;
last by apply leq_trans with (n := t2).
rewrite > big_cat_nat with (p := t2') (n := t2); try (by done); simpl.
 by rewrite addnC addnA; apply leq_addr.
+ by rewrite addnC addnA; apply leq_addr.
Qed.
Lemma leq_sum_nat m n (P : pred nat) (E1 E2 : nat > nat) :
@@ 106,7 +25,7 @@ Section ExtraLemmas.
Proof.
intros LE.
rewrite big_nat_cond [\sum_(_ <= _ < _ P _)_]big_nat_cond.
 by apply leq_sum; move => j /andP [IN H]; apply LE.
+ by apply leq_sum; move => j /andP [IN H]; apply LE.
Qed.
Lemma leq_sum_seq (I: eqType) (r: seq I) (P : pred I) (E1 E2 : I > nat) :
@@ 115,7 +34,7 @@ Section ExtraLemmas.
Proof.
intros LE.
rewrite big_seq_cond [\sum_(_ < _ P _)_]big_seq_cond.
 by apply leq_sum; move => j /andP [IN H]; apply LE.
+ by apply leq_sum; move => j /andP [IN H]; apply LE.
Qed.
Lemma sum_nat_eq0_nat (T : eqType) (F : T > nat) (r: seq T) :
@@ 128,7 +47,7 @@ Section ExtraLemmas.
first by rewrite big_const_seq iter_addn mul0n addn0 leqnn.
intro i; rewrite andbT; intros IN.
specialize (ZERO i); rewrite IN in ZERO.
 by move: ZERO => /implyP ZERO; apply/eqP; apply ZERO.
+ by move: ZERO => /implyP ZERO; apply/eqP; apply ZERO.
}
{
apply negbT in ZERO; rewrite has_predC in ZERO.
@@ 136,7 +55,7 @@ Section ExtraLemmas.
rewrite (big_rem x) /=; last by done.
symmetry; apply negbTE; rewrite neq_ltn; apply/orP; right.
apply leq_trans with (n := F x); last by apply leq_addr.
 by rewrite lt0n.
+ by rewrite lt0n.
}
Qed.
@@ 153,7 +72,7 @@ Section ExtraLemmas.
case TRUE: (P i); last by done.
move: (REDUCE i (conj LE TRUE)) => [LE' TRUE'].
rewrite (big_rem i); last by rewrite mem_index_iota.
 by rewrite TRUE' eq_refl.
+ by rewrite TRUE' eq_refl.
}
{
apply leq_sum_nat; intros i LE TRUE.
@@ 162,12 +81,279 @@ Section ExtraLemmas.
{
rewrite big_nat_cond big1; first by done.
move => i' /andP [LE'' _]; case EQ: (_ == _); last by done.
 by move: EQ => /eqP EQ; subst; rewrite LE'' in LE'.
+ by move: EQ => /eqP EQ; subst; rewrite LE'' in LE'.
}
rewrite (bigD1_seq i) /=; [  by rewrite mem_index_iota  by rewrite iota_uniq ].
rewrite eq_refl big1; first by done.
 by move => i' /negbTE NEQ; rewrite NEQ.
+ by move => i' /negbTE NEQ; rewrite NEQ.
}
Qed.
End ExtraLemmas.
\ No newline at end of file
+ Lemma sum_seq_gt0P:
+ forall (T:eqType) (r: seq T) (F: T > nat),
+ reflect (exists i, i \in r /\ 0 < F i) (0 < \sum_(i < r) F i).
+ Proof.
+ intros; apply: (iffP idP); intros.
+ {
+ induction r; first by rewrite big_nil in H.
+ destruct (F a > 0) eqn:POS.
+ exists a; split; [by rewrite in_cons; apply/orP; left  by done].
+ apply negbT in POS; rewrite leqNgt leqn0 in POS; move: POS => /eqP POS.
+ rewrite big_cons POS add0n in H. clear POS.
+ feed IHr; first by done. move: IHr => [i [IN POS]].
+ exists i; split; [by rewrite in_cons; apply/orP;right  by done].
+ }
+ {
+ move: H => [i [IN POS]].
+ rewrite (big_rem i) //=.
+ apply leq_trans with (F i); [by done  by rewrite leq_addr].
+ }
+ Qed.
+
+ (* Trivial identity: any sum of zeros is zero. *)
+ Lemma sum0 m n:
+ \sum_(m <= i < n) 0 = 0.
+ Proof.
+ by rewrite big_const_nat iter_addn mul0n addn0 //.
+ Qed.
+
+ (* A sum of natural numbers equals zero iff all terms are zero. *)
+ Lemma big_nat_eq0 m n F:
+ \sum_(m <= i < n) F i = 0 <> (forall i, m <= i < n > F i = 0).
+ Proof.
+ split.
+  rewrite /index_iota => /eqP.
+ rewrite sum_nat_eq0_nat => /allP ZERO i.
+ rewrite mem_index_iota /index_iota => IN.
+ by apply/eqP; apply ZERO.
+  move=> ZERO.
+ have >: \sum_(m <= i < n) F i = \sum_(m <= i < n) 0
+ by apply eq_big_nat => //.
+ by apply sum0.
+ Qed.
+
+ Lemma leq_pred_sum:
+ forall (T:eqType) (r: seq T) (P1 P2: pred T) F,
+ (forall i, P1 i > P2 i) >
+ \sum_(i < r  P1 i) F i <=
+ \sum_(i < r  P2 i) F i.
+ Proof.
+ intros.
+ rewrite big_mkcond [in X in _ <= X]big_mkcond//= leq_sum //.
+ intros i _.
+ destruct P1 eqn:P1a; destruct P2 eqn:P2a; [by done   by done  by done].
+ exfalso.
+ move: P1a P2a => /eqP P1a /eqP P2a.
+ rewrite eqb_id in P1a; rewrite eqbF_neg in P2a.
+ move: P2a => /negP P2a.
+ by apply P2a; apply H.
+ Qed.
+
+ Lemma sum_notin_rem_eqn:
+ forall (T:eqType) (a: T) xs P F,
+ a \notin xs >
+ \sum_(x < xs  P x && (x != a)) F x = \sum_(x < xs  P x) F x.
+ Proof.
+ intros ? ? ? ? ? NOTIN.
+ induction xs; first by rewrite !big_nil.
+ rewrite !big_cons.
+ rewrite IHxs; clear IHxs; last first.
+ { apply/memPn; intros y IN.
+ move: NOTIN => /memPn NOTIN.
+ by apply NOTIN; rewrite in_cons; apply/orP; right.
+ }
+ move: NOTIN => /memPn NOTIN.
+ move: (NOTIN a0) => NEQ.
+ feed NEQ; first by (rewrite in_cons; apply/orP; left).
+ by rewrite NEQ Bool.andb_true_r.
+ Qed.
+
+ (* We prove that if any element of a set r is bounded by constant const,
+ then the sum of the whole set is bounded by [const * size r]. *)
+ Lemma sum_majorant_constant:
+ forall (T: eqType) (r: seq T) (P: pred T) F const,
+ (forall a, a \in r > P a > F a <= const) >
+ \sum_(j < r  P j) F j <= const * (size [seq j < r  P j]).
+ Proof.
+ clear; intros.
+ induction r; first by rewrite big_nil.
+ feed IHr.
+ { intros; apply H.
+  by rewrite in_cons; apply/orP; right.
+  by done. }
+ rewrite big_cons.
+ destruct (P a) eqn:EQ.
+ { rewrite cat1s filter_cat size_cat.
+ rewrite mulnDr.
+ apply leq_add; last by done.
+ rewrite size_filter.
+ simpl; rewrite addn0.
+ rewrite EQ muln1.
+ apply H; last by done.
+ by rewrite in_cons; apply/orP; left.
+ }
+ { apply leq_trans with (const * size [seq j < r  P j]); first by done.
+ rewrite leq_mul2l; apply/orP; right.
+ rewrite cat1s filter_cat size_cat.
+ by rewrite leq_addl.
+ }
+ Qed.
+
+ (* We prove that if for any element x of a set xs the following two statements hold
+ (1) [F1 x] is less than or equal to [F2 x] and (2) the sum [F1 x_1, ..., F1 x_n]
+ is equal to the sum of [F2 x_1, ..., F2 x_n], then [F1 x] is equal to [F2 x] for
+ any element x of xs. *)
+ Lemma sum_majorant_eqn:
+ forall (T: eqType) xs F1 F2 (P: pred T),
+ (forall x, x \in xs > P x > F1 x <= F2 x) >
+ \sum_(x < xs  P x) F1 x = \sum_(x < xs  P x) F2 x >
+ (forall x, x \in xs > P x > F1 x = F2 x).
+ Proof.
+ clear.
+ intros T xs F1 F2 P H1 H2 x IN PX.
+ induction xs; first by done.
+ have Fact: \sum_(j < xs  P j) F1 j <= \sum_(j < xs  P j) F2 j.
+ { rewrite [in X in X <= _]big_seq_cond [in X in _ <= X]big_seq_cond leq_sum //.
+ move => y /andP [INy PY].
+ apply: H1; last by done.
+ by rewrite in_cons; apply/orP; right. }
+ feed IHxs.
+ { intros x' IN' PX'.
+ apply H1; last by done.
+ by rewrite in_cons; apply/orP; right. }
+ rewrite big_cons [RHS]big_cons in H2.
+ have EqLeq: forall a b c d, a + b = c + d > a <= c > b >= d.
+ { clear; intros.
+ rewrite leqNgt; apply/negP; intros H1.
+ move: H => /eqP; rewrite eqn_leq; move => /andP [LE GE].
+ move: GE; rewrite leqNgt; move => /negP GE; apply: GE.
+ by apply leq_trans with (a + d); [rewrite ltn_add2l  rewrite leq_add2r]. }
+ move: IN; rewrite in_cons; move => /orP [/eqP EQ  IN].
+ { subst a.
+ rewrite PX in H2.
+ specialize (H1 x).
+ feed_n 2 H1; [ by rewrite in_cons; apply/orP; left  by done  ].
+ move: (EqLeq
+ (F1 x) (\sum_(j < xs  P j) F1 j)
+ (F2 x) (\sum_(j < xs  P j) F2 j) H2 H1) => Q.
+ have EQ: \sum_(j < xs  P j) F1 j = \sum_(j < xs  P j) F2 j.
+ { by apply/eqP; rewrite eqn_leq; apply/andP; split. }
+ by move: H2 => /eqP; rewrite EQ eqn_add2r; move => /eqP EQ'.
+ }
+ { destruct (P a) eqn:PA; last by apply IHxs.
+ apply: IHxs; last by done.
+ specialize (H1 a).
+ feed_n 2 (H1); [ by rewrite in_cons; apply/orP; left  by done  ].
+ move: (EqLeq
+ (F1 a) (\sum_(j < xs  P j) F1 j)
+ (F2 a) (\sum_(j < xs  P j) F2 j) H2 H1) => Q.
+ by apply/eqP; rewrite eqn_leq; apply/andP; split.
+ }
+ Qed.
+
+ (* We prove that the sum of Δ ones is equal to Δ. *)
+ Lemma sum_of_ones:
+ forall t Δ,
+ \sum_(t <= x < t + Δ) 1 = Δ.
+ Proof.
+ intros.
+ simpl_sum_const.
+ rewrite addnC addnBA; last by done.
+ by rewrite subnn addn0.
+ 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.
+
+ Lemma telescoping_sum :
+ forall (T: Type) (F: T>nat) r (x0: T),
+ (forall i, i < (size r).1 > F (nth x0 r i) <= F (nth x0 r i.+1)) >
+ F (nth x0 r (size r).1)  F (nth x0 r 0) =
+ \sum_(0 <= i < (size r).1) (F (nth x0 r (i.+1))  F (nth x0 r i)).
+ Proof.
+ intros T F r x0 ALL.
+ have ADD1 := big_add1.
+ have RECL := big_nat_recl.
+ specialize (ADD1 nat 0 addn 0 (size r) (fun x => true) (fun i => F (nth x0 r i))).
+ specialize (RECL nat 0 addn (size r).1 0 (fun i => F (nth x0 r i))).
+ rewrite sum_diff; last by ins.
+ rewrite addmovr; last by rewrite [_.1]add0n; apply prev_le_next; try rewrite add0n leqnn.
+ rewrite subh1; last by apply leq_sum_nat; move => i /andP [_ LT] _; apply ALL.
+ rewrite addnC RECL //.
+ rewrite addmovl; last by rewrite big_nat_recr // {1}[\sum_(_ <= _ < _) _]addn0; apply leq_add.
+ by rewrite addnC big_nat_recr.
+ Qed.
+
+ Lemma leq_sum_sub_uniq :
+ forall (T: eqType) (r1 r2: seq T) F,
+ uniq r1 >
+ {subset r1 <= r2} >
+ \sum_(i < r1) F i <= \sum_(i < r2) F i.
+ Proof.
+ intros T r1 r2 F UNIQ SUB; generalize dependent r2.
+ induction r1 as [ x r1' IH]; first by ins; rewrite big_nil.
+ {
+ intros r2 SUB.
+ assert (IN: x \in r2).
+ by apply SUB; rewrite in_cons eq_refl orTb.
+ simpl in UNIQ; move: UNIQ => /andP [NOTIN UNIQ]; specialize (IH UNIQ).
+ destruct (splitPr IN).
+ rewrite big_cat 2!big_cons /= addnA [_ + F x]addnC addnA leq_add2l.
+ rewrite mem_cat in_cons eq_refl in IN.
+ rewrite big_cat /=.
+ apply IH; red; intros x0 IN0.
+ rewrite mem_cat.
+ feed (SUB x0); first by rewrite in_cons IN0 orbT.
+ rewrite mem_cat in_cons in SUB.
+ move: SUB => /orP [SUB1  /orP [/eqP EQx  SUB2]];
+ [by rewrite SUB1   by rewrite SUB2 orbT].
+ by rewrite EQx IN0 in NOTIN.
+ }
+ Qed.
+
+End SumArithmetic.
\ No newline at end of file