From f5252f57fedc06a1942fb6ddd836fde9a5963690 Mon Sep 17 00:00:00 2001 From: Sergei Bozhko <sbozhko@mpi-sws.org> Date: Sat, 5 Apr 2025 00:24:19 +0200 Subject: [PATCH] prove sRTA (starting with a non-IID system) --- rt/analysis/pRTA/pRTA_full.v | 102 +++ rt/analysis/scheduler_properties.v | 365 ++++++++ rt/analysis/transformation_properties.v | 1076 +++++++++++++++++++++++ rt/analysis/work_bound.v | 6 +- util/seq.v | 179 ++++ 5 files changed, 1725 insertions(+), 3 deletions(-) create mode 100644 rt/analysis/pRTA/pRTA_full.v create mode 100644 rt/analysis/scheduler_properties.v create mode 100644 rt/analysis/transformation_properties.v create mode 100644 util/seq.v diff --git a/rt/analysis/pRTA/pRTA_full.v b/rt/analysis/pRTA/pRTA_full.v new file mode 100644 index 0000000..5068a5e --- /dev/null +++ b/rt/analysis/pRTA/pRTA_full.v @@ -0,0 +1,102 @@ +(* --------------------------------- ProBsa --------------------------------- *) +From probsa.rt.analysis Require Export transformation_properties. +From probsa.rt.analysis Require Export scheduler_properties. +From probsa.rt.analysis.pRTA Require Export pRTA. + +(* ---------------------------------- Main ---------------------------------- *) +Section ProbabilisticRTA. + + Context {Task : TaskType} + {FP : FP_policy Task} + {D : TaskDeadline Task} + {T : SporadicModel Task} + {pWCET_pmf : ProbWCET Task}. + + Hypothesis H_priority_is_total : total FP. + Hypothesis H_priority_is_reflexive : reflexive hep_task. + Hypothesis H_priority_is_transitive : transitive hep_task. + + Variable ts : seq Task. + Hypothesis H_ts_uniq : uniq ts. + + Hypothesis H_restricted_deadlines : restricted_deadlines ts. + Hypothesis H_valid_sporadic : valid_taskset_inter_arrival_times ts. + + Variable tsk : Task. + Hypothesis H_tsk_in_ts : tsk \in ts. + + Context {Ω} {μ : measure Ω}. + + Context {Job : finType} + {job_cost : JobCostRV Job Ω μ} + {job_arrival : JobArrivalRV Job Ω μ} + {job_task : JobTask Job Task}. + Hypothesis H_arrivals_agree_with_costs : arrivals_cost_consistent. + + Variable h : instant. + Hypothesis H_horizon_after_deadlines : + forall j ω, (odflt0 (job_deadline j) ω < h)%nat. + + Hypothesis H_all_jobs_from_ts : forall j, job_task j \in ts. + Hypothesis H_sporadic : pr_taskset_respects_sporadic_task_model ts. + Hypothesis H_axiomatic_pWCET : axiomatic_pWCET μ. + + (** Here, [FP_FP_sched] is an implementation of a fully preemptive + FP scheduler with the classical notion of readiness and where + jobs are terminated if a deadline is missed. The theorem below + makes use of several properties of the scheduler, such as work + conservation. All necessary properties are proven in + [probsa.rt.analysis.scheduler_properties]. *) + Let 𝓡 j := response_time (compute_pr_schedule FP_FP_sched) (Some h) j. + + (** Consider a job of task [tsk]. *) + Variable j : Job. + Hypothesis H_job_of_task : job_of_task tsk j. + + Theorem probabilistic_rta_fp_fp : + ℙ<μ>{[ D tsk ⟨<⟩ 𝓡 j ]} <= Λ ts tsk. + Proof. + have TOT : total_priorities + by intros ? ?; unfold hep_job_at, JLFP_to_JLDP, hep_job, FP_to_JLFP. + have REF : reflexive_priorities + by intros ? ?; unfold hep_job_at, JLFP_to_JLDP, hep_job, FP_to_JLFP. + have TRN : transitive_priorities + by intros ? ? ? ?; unfold hep_job_at, JLFP_to_JLDP, hep_job, FP_to_JLFP; + apply H_priority_is_transitive. + apply: Rle_trans. + { by apply probabilistic_rt_monotonicity_of_iid_pWCET => //; apply FP_FP_sched_is_rt_monotonic => //. } + { apply: probabilistic_rta_fp; eauto 1; try set (S := replace_all_pETs _). + { by apply: transformation_respects_big_horizon; intros; apply H_horizon_after_deadlines. } + { by unfold pr_work_conserving; apply FP_FP_sched_is_work_conserving. } + { by apply FP_FP_sched_respects_policy_at_preemption_point. } + { by apply FP_FP_sched_respects_jobs_come_from_arrival_sequence. } + { by apply FP_FP_sched_respects_completed_jobs_dont_execute. } + { by apply FP_FP_sched_respects_jobs_must_arrive_to_execute. } + { by apply FP_FP_sched_respects_jobs_must_be_ready_to_execute. } + { by intros; apply transformation_respects_consistent_arrivals => //; apply H_arrivals_agree_with_costs. } + { by intros ? ? ?; apply H_all_jobs_from_ts. } + { by apply: sporadic_task_model_respected. } + { by apply: replaced_pETs_are_independent. } + { intros; unfold nth_cost. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl. + destruct task_job eqn:TSK; last first. + { intros ?; apply Rge_trans with 1%R. + { by rewrite pr_xpredT_ext //; apply Rge_refl. } + { by apply Rle_ge, pr_le_1. } + } + { intros ?; apply: Rge_trans. + { apply replaced_pETs_bounded_by_pWCETs with (tsko := tsk0). + by move: TSK; intros EQ; apply nth_mem_o in EQ; apply EQ. } + { by apply Rle_refl. } + } + } + { by apply pETs_have_same_distribution. } + { by apply: replaced_pETs_are_cond_independent. } + { by intros; apply replaced_pETs_are_independent_from_arr_seq_partition. } + { by intros; apply replaced_cond_pETs_bounded_by_pWCETs. } + } + Qed. + +End ProbabilisticRTA. + +Print Assumptions probabilistic_rta_fp. diff --git a/rt/analysis/scheduler_properties.v b/rt/analysis/scheduler_properties.v new file mode 100644 index 0000000..75ecfd9 --- /dev/null +++ b/rt/analysis/scheduler_properties.v @@ -0,0 +1,365 @@ +(* --------------------------------- Prosa ---------------------------------- *) +From prosa.implementation Require Import facts.ideal_uni.prio_aware. + +(* --------------------------------- ProBsa --------------------------------- *) +From probsa.util Require Export seq. +From probsa.util.prosa Require Export prio_aware. +From probsa.rt.model Require Export scheduler. +From probsa.rt.model Require Export abort_readiness. +From probsa.rt.model.assumptions Require Export basic. +From probsa.rt.model.assumptions Require Export pr_respects_policy pr_must_be_ready pr_work_conserving. + +Local Open Scope nat_scope. + +(* ---------------------------------- Main ---------------------------------- *) +Section SustainableUniFPFP. + + Context {Job : finType} + {job_arrival : JobArrival Job} + {job_deadline : JobDeadline Job} + {JLDP : JLDP_policy Job}. + + Context {job_cost1 : JobCost Job} + {job_cost2 : JobCost Job}. + + Hypothesis H_cost_monotone : forall j, job_cost1 j >= job_cost2 j. + + Let job_ready1 := @abort_ready_instance Job _ job_arrival job_cost1 job_deadline. + Let job_ready2 := @abort_ready_instance Job _ job_arrival job_cost2 job_deadline. + + Variable arr_seq : arrival_sequence Job. + + Let sched1 := @uni_schedule Job job_cost1 job_arrival arr_seq job_ready1 fully_preemptive_model JLDP. + Let sched2 := @uni_schedule Job job_cost2 job_arrival arr_seq job_ready2 fully_preemptive_model JLDP. + + Hypothesis H_consistent_arrival_times : consistent_arrival_times arr_seq. + Hypothesis H_arrival_sequence_uniq : arrival_sequence_uniq arr_seq. + + Hypothesis H_total : forall t, total (hep_job_at t). + Hypothesis H_reflexive : forall t, reflexive (hep_job_at t). + Hypothesis H_transitive : forall t, transitive (hep_job_at t). + + Section ScheduledAtMonotone. + + Variables j : Job. + Variables t : instant. + + Hypothesis H_j_sched1 : scheduled_at sched1 j t. + Hypothesis H_j_not_completed_sched2 : ~~ completed_by sched2 j t. + + Hypothesis H_service_monotone_wrt_schedules : + forall (j : Job), + ~~ completed_by sched2 j t -> + service sched1 j t <= service sched2 j t. + + Local Lemma j_scheduled_at_t_in_sched2 : + scheduled_at sched2 j t. + Proof. + move: (H_j_sched1) => SUPR; apply scheduled_job_is_supremum in SUPR; last first. + { by rewrite /preemption_time; destruct (uni_schedule _ _). } + apply supremum_monotone_wrt_subset + with (xs := @jobs_backlogged_at + _ _ _ _ _ arr_seq + match t return _ with + | O => @empty_schedule _ (ideal.processor_state _) None + | S t' => @schedule_up_to + _ _ (@allocation_at + _ _ _ arr_seq _ _ (@choose_highest_prio_job _ JLDP)) + None t' + end t + ) in SUPR; try done. + { apply scheduled_job_is_supremum_new in SUPR. + { by apply SUPR. } + { by rewrite /preemption_time; destruct (uni_schedule _ _). } + } + { by rewrite filter_uniq //; apply arrivals_uniq => //. } + { apply seq.subseq_filter => s IN. + destruct t. + { rewrite /backlogged !scheduled_at_def //=. + destruct (0 < _); last first. + { by rewrite !andbT andbF. } + { rewrite !andbT /pending. + destruct has_arrived; last by rewrite andFb. + rewrite !andTb /completed_by -!ltnNge => SERV. + apply: leq_trans; first apply: SERV. + by apply H_cost_monotone. + } + } + { clear SUPR H_j_sched1. + rewrite /backlogged !scheduled_at_def !schedule_up_to_empty //= !andbT. + destruct (_ < _ ); last by rewrite andbF. + rewrite !andbT /pending; destruct has_arrived; last by rewrite andFb. + rewrite !andTb; apply contra => COMPI. + have [COMP2 | NCOMP2] := boolP (@completed_by _ _ (sched2) job_cost2 s i.+1). + { apply: leq_trans; first by apply: COMP2. + rewrite /sched1 /service /service_during big_nat_cond [X in _ <= X]big_nat_cond. + apply leq_sum => k /andP [/andP [_ L] _]. + by rewrite !service_at_def; erewrite schedule_up_to_identical_prefix; [ | | apply L]. + } + feed (H_service_monotone_wrt_schedules s); [ by eassumption | clear NCOMP2]. + apply: leq_trans; [apply: leq_trans; last by apply COMPI | ]; first by apply H_cost_monotone. + apply: leq_trans; [apply: leq_trans; last by apply H_service_monotone_wrt_schedules | ]. + { rewrite /sched1 /service /service_during big_nat_cond [X in _ <= X]big_nat_cond. + apply leq_sum => k /andP [/andP [_ L] _]. + rewrite !service_at_def. + by erewrite schedule_up_to_identical_prefix; [ | | apply L] => //. + } + { rewrite /sched1 /service /service_during big_nat_cond [X in _ <= X]big_nat_cond. + apply leq_sum => k /andP [/andP [_ L] _]. + rewrite !service_at_def. + by erewrite schedule_up_to_identical_prefix; [ | | apply L] => //. + } + } + } + { have VNPR : valid_nonpreemptive_readiness job_ready1 by intros ?. + have NCR : nonclairvoyant_readiness job_ready1 + by intros ? ? ? ? ? ? ? => //=; f_equal; apply: identical_prefix_pending; eauto 1. + have USV := @uni_schedule_valid Job _ _ arr_seq job_ready1 NCR fully_preemptive_model VNPR JLDP. + destruct USV as [JFAS MBR]. + have HA : has_arrived j t by apply jobs_must_arrive_to_be_ready in MBR; apply MBR. + have GED : t < prosa.behavior.job.job_deadline j + by apply MBR in H_j_sched1; move: H_j_sched1 => /andP [_ DEAD]. + rewrite mem_filter; apply/andP; split; last first. + { by apply arrived_between_implies_in_arrivals; [ | eapply JFAS, H_j_sched1 | apply HA ]. } + { apply/andP; split; last first. + { by destruct t; rewrite scheduled_at_def // schedule_up_to_empty. } + { apply/andP; split => //; apply/andP; split => //. + move: H_j_not_completed_sched2; apply contra => NCOMP2. + apply: leq_trans; first by apply: NCOMP2. + rewrite /sched1 /service /service_during big_nat_cond [X in _ <= X]big_nat_cond. + apply leq_sum => i /andP [/andP [_ L] _]. + destruct t; first by done. + rewrite !service_at_def. + by erewrite schedule_up_to_identical_prefix; [ | | apply L] => //. + } + } + } + Qed. + + End ScheduledAtMonotone. + + Local Lemma service_monotone_wrt_sched : + forall (j : Job) (t : instant), + ~~ completed_by sched2 j t -> + service sched1 j t <= service sched2 j t. + Proof. + intros; move: j H. + induction t; intros s. + { by rewrite /service /service_during /service_at !big_geq //=. } + { intros NCOMP. + have [COMPt | NCOMPs] := boolP (@completed_by _ _ sched2 job_cost2 s t). + { exfalso; move: NCOMP => /negP NCOMP; apply: NCOMP. + by eapply completion_monotonic; last by eassumption. + } + { have SERV := IHt _ NCOMPs. + have [SCHED1 | NSCHED1] := boolP (scheduled_at sched1 s t); last first. + { rewrite -!service_last_plus_before. + apply: leq_add; first by done. + apply leq_trans with 0; last by done. + rewrite leqn0 service_at_def eqb0. + by move: NSCHED1; rewrite scheduled_at_def. + } + { have SCHED2 : scheduled_at sched2 s t + by apply j_scheduled_at_t_in_sched2 => //. + rewrite -!service_last_plus_before. + apply: leq_add; first by done. + by move: SCHED1 SCHED2; rewrite !scheduled_at_def !service_at_def => /eqP -> /eqP ->. + } + } + } + Qed. + + Lemma sustainable_uni_fp_fp : + forall t j, + completed_by (H := job_cost1) sched1 j t -> + completed_by sched2 j t. + Proof. + intros. + have [COMP2 | NCOMP2] := boolP (@completed_by _ _ sched2 job_cost2 j t) => //. + move: (NCOMP2) => /negP NCOM; exfalso; apply: NCOM. + apply: leq_trans; last by apply service_monotone_wrt_sched. + apply: leq_trans; last by apply H. + by apply H_cost_monotone. + Qed. + +End SustainableUniFPFP. + +(** Consider a task set together with two vectors [A] and [C] + describing job arrivals and job costs respectively. The scheduler + [FP_FP_sched] defined below mirrors the behaviour of + [uni_schedule] in an environment defined by the task set, [A] and [C]. *) +Section UniScheduleAsSchedulerAC. + + Context {Task : TaskType} + {FP : FP_policy Task} + {D : TaskDeadline Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Let arr_seq (A : Job -> option instant) : arrival_sequence Job := + fun t => + [seq j <- index_enum Job | + if A j is Some ta + then t == ta + else false + ]. + + Let job_deadline (A : Job -> option nat) : JobDeadline Job := + fun (j : Job) => + odflt 0 (match A j with Some a => Some (a + D (job_task j)) | None => None end). + + Let readiness (A C : Job -> option nat) := + @abort_ready_instance + _ _ (fun j => odflt 0 (A j)) (fun j => odflt 0 (C j)) (job_deadline A). + + Let JLDP : JLDP_policy Job := + @JLFP_to_JLDP _ (@FP_to_JLFP Job Task _ FP). + + Definition FP_FP_sched : @scheduler𝗔𝗖 Job := + fun (A C : Job -> option nat) t => + @uni_schedule + Job + (fun j => odflt 0 (C j)) (fun j => odflt 0 (A j)) + (arr_seq A) + (readiness A C) + fully_preemptive_model + JLDP + t. + +End UniScheduleAsSchedulerAC. + +Section SchedulerProperties. + + Context {Task : TaskType} + {FP : FP_policy Task} + {D : TaskDeadline Task}. + + Context {Ω} {μ : measure Ω}. + Context {Job : finType} + {job_cost : JobCostRV Job Ω μ} + {job_arrival : JobArrivalRV Job Ω μ} + {job_task : JobTask Job Task}. + + Hypothesis H_total : total_priorities. + Hypothesis H_reflexive : reflexive_priorities. + Hypothesis H_transitive : transitive_priorities. + + Let pr_sched := @compute_pr_schedule Ω μ Job job_arrival job_cost FP_FP_sched. + + Lemma abortion_readiness_is_nonclairvoyant : + forall ω, @nonclairvoyant_readiness _ _ _ _ (pr_abort_ready_instance ω). + Proof. + intros ? ? ? ? ? ? ? ?. + simpl; f_equal. + by apply: identical_prefix_pending; eauto 1. + Qed. + + Lemma FP_FP_sched_respects_completed_jobs_dont_execute : + pr_completed_jobs_dont_execute pr_sched. + Proof. + intros ω. + apply: valid_schedule_implies_completed_jobs_dont_execute; eauto 1. + apply: np_schedule_valid. + { by apply abortion_readiness_is_nonclairvoyant. } + { by intros *; apply: supremum_in. } + { by unfold job_preemptable, fully_preemptive_model. } + Qed. + + Lemma FP_FP_sched_respects_jobs_must_arrive_to_execute : + pr_jobs_must_arrive_to_execute pr_sched. + Proof. + intros ω. + apply: valid_schedule_implies_jobs_must_arrive_to_execute; eauto 1. + apply: np_schedule_valid. + { by apply abortion_readiness_is_nonclairvoyant. } + { by intros *; apply: supremum_in. } + { by unfold job_preemptable, fully_preemptive_model. } + Qed. + + Lemma FP_FP_sched_respects_jobs_come_from_arrival_sequence : + pr_jobs_come_from_arrival_sequence pr_sched. + Proof. + intros ω. + apply np_schedule_valid. + { by apply abortion_readiness_is_nonclairvoyant. } + { by intros *; apply: supremum_in. } + { by unfold job_preemptable, fully_preemptive_model. } + Qed. + + Lemma FP_FP_sched_is_work_conserving : + pr_work_conserving pr_sched pr_abort_ready_instance. + Proof. + intros ω. + apply: uni_schedule_work_conserving. + { by apply pr_consistent_arrival_times. } + { by apply abortion_readiness_is_nonclairvoyant. } + Qed. + + Lemma FP_FP_sched_respects_policy_at_preemption_point : + pr_respects_policy_at_preemption_point pr_sched pr_abort_ready_instance. + Proof. + intros ω; apply schedule_respects_policy => //. + { by apply pr_consistent_arrival_times. } + { by apply abortion_readiness_is_nonclairvoyant. } + Qed. + + Lemma FP_FP_sched_respects_jobs_must_be_ready_to_execute : + pr_jobs_must_be_ready_to_execute pr_sched pr_abort_ready_instance. + Proof. + intros ?. + apply np_schedule_valid. + { by apply abortion_readiness_is_nonclairvoyant. } + { by intros *; apply: supremum_in. } + { by unfold job_preemptable, fully_preemptive_model. } + Qed. + + Lemma FP_FP_sched_is_rt_monotonic : + forall horizon, + rt_monotonic_scheduler (Some horizon) FP_FP_sched. + Proof. + intros * A C ju j r c1 c2 LE. + set (Cs := update C ju c1); set (Cl := update C ju c2). + have UNI : + forall t j, + @completed_by _ _ (FP_FP_sched A Cl) (fun j => odflt 0 (Cl j)) j t -> + @completed_by _ _ (FP_FP_sched A Cs) (fun j => odflt 0 (Cs j)) j t. + { apply sustainable_uni_fp_fp; eauto 1; last first. + { by intros ?; rewrite filter_uniq // index_enum_uniq. } + { intros s t; rewrite /arrives_at /arrivals_at mem_filter. + destruct (A s) eqn:EQ; last by done. + rewrite /prosa.behavior.job.job_arrival EQ //=. + by move=> /andP [/eqP -> _]. + } + { by intros ?; rewrite /Cs /Cl /update; destruct (j0 == ju); [apply LE | done]. } + } + unfold FP_FP_sched, scheduler𝗔𝗖_to_rt𝗔𝗖 in *; simpl in *. + destruct (scheduler.min_completion_time). + { destruct (A j) as [aj | ] eqn:Aj; last by done. + destruct s as [rt1 [COMP1 MIN1]]. + have [LErt1|GTrt1] := leqP horizon rt1. + { intros _. + destruct (scheduler.min_completion_time); last by done. + destruct s as [rt2 [COMP2 MIN2]]. + destruct (horizon <= rt2) eqn:GTrt2 => //. + move: GTrt2 => /negP/negP; rewrite -ltnNge => GTrt2. + exfalso; unfold FP_FP_sched, scheduler𝗔𝗖_to_completed𝗔𝗖 in *. + apply (MIN1 rt2); first by apply/leP; apply: leq_trans; [apply GTrt2 | apply LErt1]. + by apply UNI; apply COMP2. } + { rewrite //= ltn_subRL => LTrt1. + destruct (scheduler.min_completion_time); last by done. + destruct s as [rt2 [COMP2 MIN2]]. + destruct (horizon <= rt2) eqn:GTrt2 => //. + rewrite //= ltn_subRL; move_neq_up GErt2; unfold FP_FP_sched, scheduler𝗔𝗖_to_completed𝗔𝗖 in *. + apply (MIN1 rt2); first by apply/leP; apply: leq_ltn_trans; [apply GErt2 | apply LTrt1]. + by apply UNI; apply COMP2. } + } + { destruct (A j) as [aj | ] eqn:Aj; last by done. + intros _; destruct (scheduler.min_completion_time); last by done. + destruct s as [rt2 [COMP2 MIN2]]. + exfalso; apply: (n rt2); unfold scheduler𝗔𝗖_to_completed𝗔𝗖 in *. + by apply UNI, COMP2. + } + Qed. + +End SchedulerProperties. diff --git a/rt/analysis/transformation_properties.v b/rt/analysis/transformation_properties.v new file mode 100644 index 0000000..f809045 --- /dev/null +++ b/rt/analysis/transformation_properties.v @@ -0,0 +1,1076 @@ +(* --------------------------------- ProBsa --------------------------------- *) +From probsa.rt.model Require Export pRBF assumptions.basic. +From probsa.rt.analysis Require Export axiomatic_pWCET_full. + +Local Open Scope nat_scope. + +(* ---------------------------------- Main ---------------------------------- *) +(** In this file we prove lemmas that establish properties of a system + after the axiomatic-pWCET transformation .*) + +(** In this section we prove that, given a system that satisfies the + sporadic task model, a new system generated by the transformation + will also satisfy the sporadic task model. That is, the + transformation respects the sporadic model. *) +Section TransformationRespectsSporadicTaskModel. + + (** Consider any type of tasks with a notion of pWCET ... *) + Context {Task : TaskType} + {D : TaskDeadline Task} + {T : SporadicModel Task} + {pWCET_pmf : ProbWCET Task}. + + (** ...and their jobs. *) + Context {Job : finType} + {job_task : JobTask Job Task}. + + (** Consider a scheduling algorithm [ζ] that receives two vectors: a + vector of arrival times [𝗔] and a vector of job costs [𝗖]. *) + Variable ζ : @scheduler𝗔𝗖 Job. + + (** Let [sched] denote a schedule generated by [ζ] for a given + system [S]. *) + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + (** Most of the properties are proved by a three-step + procedure. First, we show that a single step of the + transformation preserves the property in question. Second, we + show that [n] steps of the transformation preserve the + property. Finally, we show that if [n = |jobs|], then the + property holds for the final system. *) + Section Step1. + + (** Consider a system [S]. *) + Variable S : @system Job. + + (** Next, consider two arbitrary jobs: job [j] and job [j_rep], + whose pET we modify. *) + Variable (j_rep : Job) (j : Job). + + (** Suppose we use the construction [replace_job_pET] presented + in [probsa/rt/analysis/pETs_to_pWCETs] to replace the + execution cost of given job [j_rep]. Let [S'] denote the + resulting system. *) + Let S' : system := replace_job_pET j_rep S. + + (** Then, given a task set [ts], ...*) + Variable ts : seq Task. + + (** ... if [S] respects the sporadic task model, then [S'] also + satisfies the sporadic task model. *) + Lemma sporadic_task_model_respected_step : + pr_taskset_respects_sporadic_task_model (job_arrival := 𝓐_of S) ts -> + pr_taskset_respects_sporadic_task_model (job_arrival := 𝓐_of S') ts . + Proof. + intros * SPO; unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + intros [ω n]. + specialize (SPO ω). + intros ? IN j1 j2 NEQ ARR1 ARR2 TSK1 TSK2 LE. + by apply SPO => //. + Qed. + + End Step1. + + (** In the next step, we apply the transformation to an arbitrary + subset of jobs [jobs].*) + Section Step2. + + Variables (ts : seq Task) (jobs : seq Job) (S : @system Job). + Let S' : system := foldr replace_job_pET S jobs. + + Lemma sporadic_task_model_respected_steps : + pr_taskset_respects_sporadic_task_model (job_arrival := 𝓐_of S) ts -> + pr_taskset_respects_sporadic_task_model (job_arrival := 𝓐_of S') ts. + Proof. + induction jobs as [| j_rep jobs']; destruct S as [Ω μ 𝓐 𝓒]; first by done. + intros SPO ? ?. + unfold S' in *; clear S'. + simpl in ω. + apply sporadic_task_model_respected_step. + apply IHjobs'. + by apply SPO. + Qed. + + End Step2. + + (** Finally, we apply the previous lemma to a set of jobs that + coincides with the set of all jobs. *) + Section Step3. + + Variable S : @system Job. + Let S' := replace_all_pETs S. + + Variable ts : seq Task. + + Lemma sporadic_task_model_respected : + pr_taskset_respects_sporadic_task_model (job_arrival := 𝓐_of S) ts -> + pr_taskset_respects_sporadic_task_model (job_arrival := 𝓐_of S') ts. + Proof. + by intros; apply sporadic_task_model_respected_steps. + Qed. + + End Step3. + +End TransformationRespectsSporadicTaskModel. + +(** In the following, we repeat the same procedure for all the + necessary properties. Next, we prove that the transformation + respects the assumption about the termination horizon of the + system. *) +Section TransformationRespectsBigHorizon. + + Context {Task : TaskType} + {D : TaskDeadline Task} + {T : SporadicModel Task} + {pWCET_pmf : ProbWCET Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Let job_deadline (S : system) (j : Job) := + @job_deadline _ _ _ (@job_deadline_from_task_deadline _ _ _ _ D (𝓐_of S) _) j. + + Variable ζ : @scheduler𝗔𝗖 Job. + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + Section Step1. + + Variable (S : @system Job) (j_rep : Job) (j : Job). + Let S' : system := replace_job_pET j_rep S. + + Variable h : instant. + Hypothesis BIG : forall (ω : Ω_of S), odflt0 (job_deadline S j) ω < h. + + Lemma transformation_respects_big_horizon_step : + forall (ω : Ω_of S'), odflt0 (job_deadline S' j) ω < h. + Proof. + unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + intros [ω a]. + by apply BIG. + Qed. + + End Step1. + + Section Step2. + + Variables (S : @system Job) (jobs : seq Job) (j : Job). + Let S' : system := foldr replace_job_pET S jobs. + + Variable h : instant. + Hypothesis H_horizon_big : forall (ω : Ω_of S), odflt0 (job_deadline S j) ω < h. + + Lemma transformation_respects_big_horizon_steps : + forall ω, odflt0 (job_deadline S' j) ω < h. + Proof. + induction jobs as [| j_rep jobs']; first by done. + unfold S' in *; clear S'. + intros ω => //=. + apply transformation_respects_big_horizon_step. + by intros; apply IHjobs'. + Qed. + + End Step2. + + Section Step3. + + Variable S : @system Job. + Let S' : system := replace_all_pETs S. + + Variable h : instant. + Hypothesis H_horizon_big : forall (j : Job) (ω : Ω_of S), odflt0 (job_deadline S j) ω < h. + + Lemma transformation_respects_big_horizon : + forall (j : Job) (ω : Ω_of S'), + odflt0 (job_deadline S' j) ω < h. + Proof. + by intros; apply transformation_respects_big_horizon_steps. + Qed. + + End Step3. + +End TransformationRespectsBigHorizon. + +Section TransformationRespectsArrivalsCostConsistent. + + Context {Task : TaskType} + {D : TaskDeadline Task} + {T : SporadicModel Task} + {pWCET_pmf : ProbWCET Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Variable ζ : @scheduler𝗔𝗖 Job. + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + Section Step1. + + Variable (S : @system Job) (j_rep : Job) (j : Job). + Let S' : system := replace_job_pET j_rep S. + + Lemma transformation_respects_consistent_arrivals_step : + arrivals_cost_consistent (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S) -> + arrivals_cost_consistent (job_arrival := 𝓐_of S') (job_cost := 𝓒_of S'). + Proof. + intros SOME * ARR; unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + destruct ω as [ω n]. + destruct (_ == _) eqn:EQ; first by done. + by apply SOME. + Qed. + + End Step1. + + Section Step2. + + Variables (jobs_rep : seq Job) (S : @system Job). + Let S' : system := foldr replace_job_pET S jobs_rep. + + Lemma transformation_respects_consistent_arrivals_steps : + arrivals_cost_consistent (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S) -> + arrivals_cost_consistent (job_arrival := 𝓐_of S') (job_cost := 𝓒_of S'). + Proof. + induction jobs_rep as [| j_rep jobs]; destruct S as [Ω μ 𝓐 𝓒]. + { by simpl in *. } + { simpl; intros. + apply transformation_respects_consistent_arrivals_step. + by apply IHjobs, H. + } + Qed. + + End Step2. + + Section ProofOfLemmas3. + + Variable S : @system Job. + Let S' := replace_all_pETs S. + + Lemma transformation_respects_consistent_arrivals : + arrivals_cost_consistent (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S) -> + arrivals_cost_consistent (job_arrival := 𝓐_of S') (job_cost := 𝓒_of S'). + Proof. + by intros; apply transformation_respects_consistent_arrivals_steps. + Qed. + + End ProofOfLemmas3. + +End TransformationRespectsArrivalsCostConsistent. + +Section TransformationPreservesArrivalSequence. + + Context {Task : TaskType} + {D : TaskDeadline Task} + {pWCET_pmf : ProbWCET Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Variable ζ : @scheduler𝗔𝗖 Job. + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + Variable (S : @system Job) (j_rep : Job). + Let S' : system := replace_job_pET j_rep S. + + Lemma transformation_preserves_arr_seq : + forall ξ' : imgT (arr_seq (job_arrival := 𝓐_of S')), + exists ξ : imgT (arr_seq (job_arrival := 𝓐_of S)), + forall t, proj1_sig ξ t = proj1_sig ξ' t. + Proof. + intros [ξ INS']. + unshelve econstructor. + { unshelve econstructor; first by apply ξ. + unfold S' in *; clear S'. + destruct S as [Ω μ A C], pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + move: (INS'); rewrite !unfold_in => /exCP [[ω n] /eqP EQ]. + apply/exCP; exists ω; rewrite -EQ; apply/eqP. + have FE := @FunctionalExtensionality.functional_extensionality nat (seq Job) (arr_seq ω) (arr_seq (ω, n)). + by apply: FE => t; reflexivity. + } + { by simpl; intros; reflexivity. } + Qed. + +End TransformationPreservesArrivalSequence. + +(** In this section we show that in the transformed system all pETs + (related to jobs of the same task) have the same distribution. *) +Section TransformationEnsuresIdenticalCosts. + + Context {Task : TaskType} + {D : TaskDeadline Task} + {pWCET_pmf : ProbWCET Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Variable ζ : @scheduler𝗔𝗖 Job. + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + Section Step1. + + Variable (S : @system Job) (j_rep : Job) (j : Job). + Let S' := replace_job_pET j_rep S. + + Section CostBoundedByPWCET. + + Variable tsk : Task. + Hypothesis H_job_of_task : job_of_task tsk j_rep. + + Lemma replaced_pETs_bounded_by_pWCETs_step : + odflt0 (𝓒_of S' j_rep) ⪯ to_distrib pWCET_pmf tsk. + Proof. + unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + rewrite eq_refl => k. + rewrite (pr_joint_pred_eq _ _ _ (fun ω => true) (fun ω => ω <= k)). + { rewrite pr_xpredT Rmult_1_l. + by move: H_job_of_task => /eqP TSK2; rewrite /μ_tsk -TSK2; apply Rge_refl. } + { by intros [ω n]. } + Qed. + + Lemma pWCETs_bounded_by_replaced_pETs_step : + to_distrib pWCET_pmf tsk ⪯ odflt0 (𝓒_of S' j_rep). + Proof. + unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + rewrite eq_refl => k. + rewrite (pr_joint_pred_eq _ _ _ (fun ω => true) (fun ω => ω <= k)). + { rewrite pr_xpredT Rmult_1_l. + by move: H_job_of_task => /eqP TSKo; rewrite /μ_tsk -TSKo; apply Rge_refl. } + { by intros [ω n]. } + Qed. + + End CostBoundedByPWCET. + + Section CostBounds. + + Hypothesis H_jobs_neq : j_rep != j. + + Lemma nonreplaced_pETs_dont_change_1_step : + odflt0 (𝓒_of S' j) ⪯ odflt0 (𝓒_of S j). + Proof. + unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + have NEQ2 : (j_rep == j) = false by apply/eqP/eqP. + rewrite NEQ2 => k; rewrite /cdf. + rewrite (pr_joint_pred_eq _ _ _ (odflt0 (C j) ⟨<=⟩ k) (fun ω => true)). + { by rewrite pr_xpredT Rmult_1_r; apply Rge_refl. } + { by intros [ω n]; rewrite andbT. } + Qed. + + Lemma nonreplaced_pETs_dont_change_2_step : + odflt0 (𝓒_of S j) ⪯ odflt0 (𝓒_of S' j). + Proof. + unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + have NEQ2 : (j_rep == j) = false by apply/eqP/eqP. + rewrite NEQ2 => k; rewrite /cdf. + rewrite (pr_joint_pred_eq _ _ _ (odflt0 (C j) ⟨<=⟩ k) (fun ω => true)). + { by rewrite pr_xpredT Rmult_1_r; apply Rge_refl. } + { by intros [ω n]; rewrite andbT. } + Qed. + + End CostBounds. + + End Step1. + + Section Step2. + + Variable jobs_rep : seq Job. + Hypothesis H_jobs_uniq : uniq jobs_rep. + + Variable S : @system Job. + Let S' := foldr replace_job_pET S jobs_rep. + + Variables (j : Job) (tsk : Task). + Hypothesis H_j_in_reps : j \in jobs_rep. + Hypothesis H_job_of_task : job_of_task tsk j. + + Lemma replaced_pETs_bounded_by_pWCETs_steps : + odflt0 (𝓒_of S' j) ⪯ to_distrib pWCET_pmf tsk. + Proof. + induction jobs_rep as [| j_rep jobs]; destruct S as [Ω μ 𝓐 𝓒]; first by done. + unfold S' in *; clear S'. + move: H_j_in_reps; rewrite in_cons => /orP [/eqP EQ | IN] TSK. + { by subst j_rep; apply replaced_pETs_bounded_by_pWCETs_step => //. } + { apply: Rge_trans; first apply nonreplaced_pETs_dont_change_1_step. + { by apply/eqP => EQ; subst; move: H_jobs_uniq; rewrite //= IN andFb. } + apply IHjobs => //. + by move: H_jobs_uniq; simpl => /andP [_ UNIQo]; apply: UNIQo. + } + Qed. + + Lemma pWCETs_bounded_by_replaced_pETs_steps : + to_distrib pWCET_pmf tsk ⪯ odflt0 (𝓒_of S' j). + Proof. + induction jobs_rep as [| j_rep jobs]; destruct S as [Ω μ 𝓐 𝓒]; first by done. + unfold S' in *; clear S'. + move: H_j_in_reps; rewrite in_cons => /orP [/eqP EQ | IN] TSK. + { by subst j_rep; apply pWCETs_bounded_by_replaced_pETs_step => //. } + { apply: Rge_trans; last apply nonreplaced_pETs_dont_change_2_step; last first. + { by apply/eqP => EQ; subst; move: H_jobs_uniq; rewrite //= IN andFb. } + apply IHjobs => //. + by move: H_jobs_uniq; simpl => /andP [_ UNIQo]; apply: UNIQo. + } + Qed. + + End Step2. + + Section Step3. + + Variable S : @system Job. + Let S' := replace_all_pETs S. + + Lemma replaced_pETs_bounded_by_pWCETs : + forall (j : Job) (tsko : Task), + job_of_task tsko j -> + odflt0 (𝓒_of S' j) ⪯ to_distrib pWCET_pmf tsko. + Proof. + intros; apply replaced_pETs_bounded_by_pWCETs_steps => //. + - by apply index_enum_uniq. + - by apply mem_index_enum. + Qed. + + Lemma pWCETs_bounded_by_replaced_pETs : + forall (j : Job) (tsko : Task), + job_of_task tsko j -> + to_distrib pWCET_pmf tsko ⪯ odflt0 (𝓒_of S' j). + Proof. + intros; apply pWCETs_bounded_by_replaced_pETs_steps => //. + - by apply index_enum_uniq. + - by apply mem_index_enum. + Qed. + + Lemma pETs_have_same_distribution : + ∀ (j1 j2 : Job), + job_task j1 = job_task j2 -> + odflt0 (𝓒_of S' j1) ⪯ odflt0 (𝓒_of S' j2). + Proof. + intros * TSK. + apply: func_dom_trans. + { apply replaced_pETs_bounded_by_pWCETs_steps. + - by apply index_enum_uniq. + - by apply mem_index_enum. + - by rewrite /job_of_task /concept.job_task. + } + { apply pWCETs_bounded_by_replaced_pETs_steps. + - by apply index_enum_uniq. + - by apply mem_index_enum. + - by rewrite TSK /job_of_task /concept.job_task. + } + Qed. + + End Step3. + +End TransformationEnsuresIdenticalCosts. + +(** In this section, we show that, in the transformed system, all pETs + are independent. *) +Section TransformationEnsuresIndependentCosts. + + Context {Task : TaskType} + {D : TaskDeadline Task} + {pWCET_pmf : ProbWCET Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Variable ζ : @scheduler𝗔𝗖 Job. + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + Section Step1. + + Variable (S : @system Job) (j_rep : Job) (j : Job). + Let S' : system := replace_job_pET j_rep S. + + Variable jobs : seq Job. + Hypothesis H_jrep_notin_jobs : j_rep \notin jobs. + + Lemma replaced_pETs_are_independent_step : + indep2 (𝓒_of S' j_rep) (rvar_list [seq 𝓒_of S' j | j <- jobs]). + Proof. + unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + intros a b; rewrite /pr_eq. + have EQ : forall a b c, a = b -> ((a == c) = (b == c)). + { clear. intros. subst. by done. } + rewrite (pr_joint_pred_eq + _ _ _ + (fun (ω : Ω) => (rvar_list [seq C j | j <- jobs]) ω == b) + (fun (ω : nat) => Some ω == a)); last first. + { intros [ω n]; rewrite eq_refl andbC; f_equal. + simpl; apply: EQ. + induction jobs as [ | jo jobso]; first by done. + rewrite //= IHjobso; clear IHjobso; last first. + { by apply/negP; intros IN; move: (H_jrep_notin_jobs); rewrite in_cons IN orbT. } + apply/eqP; rewrite eqseq_cons; apply/andP; split; last by done. + have NEQ: j_rep == jo = false. + { by apply/negP => /eqP EQ; subst; move: (H_jrep_notin_jobs); rewrite in_cons eq_refl orTb. } + by rewrite NEQ. + } + rewrite (pr_joint_pred_eq _ _ _ xpredT (fun ω => Some ω == a)); last first. + { by rewrite eq_refl //=; intros [ω n]. } + rewrite (pr_joint_pred_eq + _ _ _ (fun (ω : Ω) => (rvar_list [seq C j | j <- jobs]) ω == b) xpredT + ); last first. + { intros [ω n]; rewrite //= andbT; apply: EQ. + induction jobs as [ | jo jobso]; first by done. + rewrite //= IHjobso; clear IHjobso; last first. + { by apply/negP; intros IN; move: (H_jrep_notin_jobs); rewrite in_cons IN orbT. } + apply/eqP; rewrite eqseq_cons; apply/andP; split; last by done. + have NEQ: j_rep == jo = false. + { by apply/negP => /eqP EQ; subst; move: H_jrep_notin_jobs; rewrite in_cons eq_refl orTb. } + by rewrite NEQ. + } + by rewrite !pr_xpredT Rmult_1_l Rmult_1_r Rmult_comm. + Qed. + + Lemma transformation_respects_independence_step : + independent [seq 𝓒_of S j | j <- jobs] -> + independent [seq 𝓒_of S' j | j <- jobs]. + Proof. + intros IND cs LEN; unfold S' in *; clear S' => //=. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + apply: eq_tr4. + { apply IND. + rewrite -!seq_ext.size_legacy size_map; rewrite -!seq_ext.size_legacy size_map in LEN. + by apply LEN. + } + { rewrite (pr_joint_pred_eq + _ _ _ (fun (ω : Ω) => (rvar_list [seq C j | j <- jobs]) ω == cs) xpredT + ); last first. + { intros [ω n]; rewrite andbT zip_foldr_andb_seq_eq; last first. + { by move: LEN; rewrite -!seq_ext.size_legacy !size_map => ->. } + move: cs LEN; clear IND. + induction jobs as [ | jo jobso]; first by intros []. + intros []; first by done. + rewrite -!seq_ext.size_legacy !size_map //= => LEN; apply eq_add_S in LEN. + rewrite IHjobso; f_equal. + { by have ->: j_rep == jo = false + by apply/negP => /eqP EQ; subst; move: (H_jrep_notin_jobs); rewrite in_cons eq_refl orTb. } + { by apply/negP; intros IN; move: (H_jrep_notin_jobs); rewrite in_cons IN orbT. } + { by rewrite -!seq_ext.size_legacy !size_map. } + } + { rewrite !pr_xpredT Rmult_1_r. + apply pr_eq_pred => ω; rewrite !unfold_in zip_foldr_andb_seq_eq; last first. + { by move: LEN; rewrite -!seq_ext.size_legacy !size_map => ->. } + f_equal; rewrite !zip_map_rvar_eq; f_equal; f_equal. + by clear; induction jobs as [ | jo jobso]; [done | rewrite //= -IHjobso]. + } + } + { f_equal; rewrite !zip_map_pr_eq. + move: cs LEN; clear IND; induction jobs as [ | jo jobso]; first by intros []. + intros []; first by done. + rewrite -!seq_ext.size_legacy !size_map //= => LEN; apply eq_add_S in LEN. + rewrite IHjobso; f_equal. + { have NEQ: j_rep == jo = false. + { by apply/negP => /eqP EQ; subst; move: (H_jrep_notin_jobs); rewrite in_cons eq_refl orTb. } + rewrite /pr_eq (pr_joint_pred_eq _ _ _ (fun ω => C jo ω == o) xpredT); last first. + { by rewrite NEQ //=; intros [ω n]; rewrite andbT. } + by rewrite pr_xpredT Rmult_1_r. + } + { by apply/negP; intros IN; move: (H_jrep_notin_jobs); rewrite in_cons IN orbT. } + { by rewrite -!seq_ext.size_legacy !size_map. } + } + Qed. + + End Step1. + + Section Step2. + + Variable jobs_rep : seq Job. + Hypothesis H_jobs_uniq : uniq jobs_rep. + + Variable S : @system Job. + Let S' : system := foldr replace_job_pET S jobs_rep. + + Lemma replaced_pETs_are_independent_steps : + independent [seq 𝓒_of S' j | j <- jobs_rep]. + Proof. + induction jobs_rep as [| j_rep jobs]; destruct S as [Ω μ 𝓐 𝓒]. + { by intros; apply independent_nil. } + { intros; simpl. + apply indep2_independent_cons. + { by apply replaced_pETs_are_independent_step; move: H_jobs_uniq => /andP [H _]. } + { apply transformation_respects_independence_step => //. + by move: H_jobs_uniq => /andP [H _]. + apply IHjobs. + by move: H_jobs_uniq => /andP [_ H]. + } + } + Qed. + + End Step2. + + Section Step3. + + Variable S : @system Job. + Let S' : system := replace_all_pETs S. + + Lemma replaced_pETs_are_independent : + independent [seq 𝓒_of S' j | j <- index_enum Job]. + Proof. + intros; apply replaced_pETs_are_independent_steps. + by apply index_enum_uniq. + Qed. + + End Step3. + +End TransformationEnsuresIndependentCosts. + +(** Finally, we show that in the transformed system, all pETs are + independent of the arrival sequence, as well as independent of + each other conditioned on an arrival sequence. *) +Section TransformationEnsuresCostsIndependentFromArrivals. + + Context {Task : TaskType} + {D : TaskDeadline Task} + {pWCET_pmf : ProbWCET Task}. + + Context {Job : finType} + {job_task : JobTask Job Task}. + + Variable ζ : @scheduler𝗔𝗖 Job. + Let sched (S : system) := compute_pr_schedule ζ (job_arrival := 𝓐_of S) (job_cost := 𝓒_of S). + + Section Step1. + + Variable (S : @system Job) (j_rep : Job) (j : Job). + Let S' : system := replace_job_pET j_rep S. + + Section IndependentArrSeq. + + Variable ξa : arrival_sequence Job. + Let ξf := ξ_fix (arr_seq (job_arrival := 𝓐_of S)) ξa. + Let ξf' := ξ_fix (arr_seq (job_arrival := 𝓐_of S')) ξa. + + Variable jobs : seq Job. + Hypothesis H_jrep_notin_jobs : j_rep \notin jobs. + + Lemma transformation_respects_pET_indep_arr_seq_cons_step : + @indep2 _ _ _ (μ_of S) + {| rvar_fun := λ ω, [seq 𝓒_of S j0 ω | j0 <- jobs] |} + {| rvar_fun := ξf |} -> + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω, [seq 𝓒_of S' j0 ω | j0 <- j_rep :: jobs] |} + {| rvar_fun := ξf' |}. + Proof. + intros IND; unfold S' in *; clear S'. + destruct S as [Ω μ A C]; destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + intros [ | c cs] b. + { rewrite //= pr_xpred0 /pr_eq eq_refl //=; symmetry. + by apply Rmult_eq_0_compat_r; apply pr_zero => [ω n]. } + { rewrite (pr_joint_pred_eq + _ _ _ + (fun (ω : Ω) => ((rvar_list [seq C j | j <- jobs]) ω == cs) && (ξf ω == b)) + (fun (ω : nat) => Some ω == c)); last first. + { intros [ω n] => //=; rewrite eq_refl eqseq_cons -andbA andbC; do 3 f_equal. + clear IND; induction jobs as [ | jo jobso]; first by done. + rewrite //= IHjobso; clear IHjobso; last first. + { by apply/negP; intros IN; move: H_jrep_notin_jobs; rewrite in_cons IN orbT. } + apply/eqP; rewrite eqseq_cons; apply/andP; split; last by done. + have NEQ: j_rep == jo = false. + { by apply/negP => /eqP EQ; subst; move: H_jrep_notin_jobs; rewrite in_cons eq_refl orTb. } + by rewrite NEQ. + } + rewrite /pr_eq (pr_joint_pred_eq + _ _ _ + (fun ω => ((rvar_list [seq C j | j <- jobs]) ω == cs)) + (fun ω => Some ω == c)); last first. + { intros [ω n] => //=; rewrite eq_refl eqseq_cons andbC; do 2 f_equal. + clear IND; induction jobs as [ | jo jobso]; first by done. + rewrite //= IHjobso; clear IHjobso; last first. + { by apply/negP; intros IN; move: H_jrep_notin_jobs; rewrite in_cons IN orbT. } + apply/eqP; rewrite eqseq_cons; apply/andP; split; last by done. + by have ->: j_rep == jo = false + by apply/negP => /eqP EQ; subst; move: H_jrep_notin_jobs; rewrite in_cons eq_refl orTb. + } + rewrite /pr_eq (pr_joint_pred_eq + _ _ _ (fun (ω : Ω) => (ξf ω == b)) (xpredT)); last first. + { by intros [ω n]; rewrite andbT; reflexivity. } + rewrite pr_xpredT Rmult_1_r Rmult_comm. + symmetry; rewrite Rmult_assoc Rmult_comm Rmult_assoc; apply Rmult_eq_compat_l; symmetry. + apply: eq_tr4; first apply (IND cs b). + { apply pr_eq_pred => ω; rewrite !unfold_in //=. + by do 2 f_equal; clear IND H_jrep_notin_jobs; + induction jobs as [ | jo jobso]; [ | rewrite //= IHjobso]. + } + { rewrite Rmult_comm; apply Rmult_eq_compat_r. + apply pr_eq_pred => ω; rewrite !unfold_in //=. + by do 2 f_equal; clear IND H_jrep_notin_jobs; + induction jobs as [ | jo jobso]; [ | rewrite //= IHjobso]. + } + } + Qed. + + Lemma transformation_respects_pET_indep_arr_seq_eq_step : + @indep2 _ _ _ (μ_of S) + {| rvar_fun := λ ω, [seq 𝓒_of S j ω | j <- jobs] |} + {| rvar_fun := ξf |} -> + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω, [seq 𝓒_of S' j ω | j <- jobs] |} + {| rvar_fun := ξf' |}. + Proof. + intros IND; unfold S' in *; clear S'. + destruct S as [Ω μ A C]; destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + intros cs b. + rewrite (pr_joint_pred_eq + _ _ _ (fun ω => ((rvar_list [seq C j | j <- jobs]) ω == cs) && (ξf ω == b)) xpredT + ); last first. + { intros [ω n] => //=. rewrite andbT; do 2 f_equal. + clear IND; induction jobs as [ | jo jobso]; first by done. + rewrite //= IHjobso; clear IHjobso; last first. + { by apply/negP; intros IN; move: H_jrep_notin_jobs; rewrite in_cons IN orbT. } + apply/eqP; rewrite eqseq_cons; apply/andP; split; last by done. + by have ->: j_rep == jo = false + by apply/negP => /eqP EQ; subst; move: H_jrep_notin_jobs; rewrite in_cons eq_refl orTb. + } + rewrite /pr_eq (pr_joint_pred_eq + _ _ _ (fun ω => ((rvar_list [seq C j | j <- jobs]) ω == cs)) xpredT + ); last first. + { intros [ω n] => //=; rewrite andbT; do 2 f_equal. + clear IND; induction jobs as [ | jo jobso]; first by done. + rewrite //= IHjobso; clear IHjobso; last first. + { by apply/negP; intros IN; move: H_jrep_notin_jobs; rewrite in_cons IN orbT. } + apply/eqP; rewrite eqseq_cons; apply/andP; split; last by done. + by have ->: j_rep == jo = false + by apply/negP => /eqP EQ; subst; move: H_jrep_notin_jobs; rewrite in_cons eq_refl orTb. + } + rewrite /pr_eq (pr_joint_pred_eq _ _ _ (fun ω => (ξf ω == b)) (xpredT)); last first. + { by intros [ω n]; rewrite andbT; reflexivity. } + rewrite pr_xpredT Rmult_comm !Rmult_1_r !Rmult_1_l. + apply: eq_tr4; first apply (IND cs b). + { apply pr_eq_pred => ω; rewrite !unfold_in //=. + by do 2 f_equal; clear IND H_jrep_notin_jobs; + induction jobs as [| jo jobso] ; [ | rewrite //= IHjobso]. } + { apply Rmult_eq_compat_r. + apply pr_eq_pred => ω; rewrite !unfold_in //=. + by do 2 f_equal; clear IND H_jrep_notin_jobs; + induction jobs as [| jo jobso]; [ | rewrite //= IHjobso]. } + Qed. + + Lemma transformation_respects_pET_indep_arr_seq_remove_step : + @indep2 _ _ _ (μ_of S) + {| rvar_fun := λ ω, [seq 𝓒_of S j0 ω | j0 <- jobs & predC1 j0 j_rep] |} + {| rvar_fun := ξf |} -> + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω, [seq 𝓒_of S' j0 ω | j0 <- jobs] |} + {| rvar_fun := ξf' |}. + Proof. + intros IND; unfold S' in *; clear S'. + destruct S as [Ω μ A C]; destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + intros cs b. + have [/eqP SEQ|SNEQ] := boolP (size cs == size jobs); last first. + { apply eq_tr3 with 0%R. + { apply pr_zero => [ω n]; apply/eqP. + rewrite eqbF_neg negb_and; apply/orP; left. + apply/negP => /eqP EQ; subst cs. + move: SNEQ => /negP SNEQ; apply: SNEQ. + by rewrite size_map. + } + { symmetry; apply Rmult_eq_0_compat_r. + apply pr_zero => [ω n]; apply/eqP => EQ; subst cs. + move: SNEQ => /negP SNEQ; apply: SNEQ. + by rewrite size_map. + } + } + set (csN := [seq p.2 | p <- zip jobs cs & j_rep != p.1]). + set (csE := [seq p.2 | p <- zip jobs cs & j_rep == p.1]). + rewrite /pr_eq (pr_joint_pred_eq + _ _ _ + (fun (ω : Ω) => ((rvar_list [seq C j | j <- jobs & j_rep != j]) ω == csN) && (ξf ω == b)) + (fun (n : nat) => [seq Some n | j <- jobs & j_rep == j] == csE) + ); last first. + { intros [ω n]; symmetry; rewrite andbC andbA. + f_equal; unfold csN, csE; clear csN csE H_jrep_notin_jobs IND. + move: cs SEQ; induction jobs as [|jo jobso]; first by intros []. + intros []; first by done. + intros; simpl. + have [/eqP EQa | NEQa] := boolP (j_rep == jo). + { by rewrite //= !eqseq_cons -IHjobso; + [rewrite andbA; f_equal | apply eq_add_S, SEQ]. } + { by rewrite //= !eqseq_cons -IHjobso; + [rewrite andbC -!andbA; f_equal; rewrite andbC; f_equal + | apply eq_add_S, SEQ]. } + } + rewrite (pr_joint_pred_eq + _ _ _ + (fun (ω : Ω) => ((rvar_list [seq C j | j <- jobs & j_rep != j]) ω == csN)) + (fun (n : nat) => [seq Some n | j <- jobs & j_rep == j] == csE) + ); last first. + { intros [ω n]; symmetry. + unfold csN, csE; clear csN csE H_jrep_notin_jobs IND; move: cs SEQ. + induction jobs as [ | jo jobso]; first by intros []. + intros []; [by done | intros; simpl]. + have [/eqP EQa | NEQa] := boolP (j_rep == jo). + { by rewrite //= !eqseq_cons -IHjobso; + [rewrite andbC -!andbA; f_equal; rewrite andbC; f_equal + | apply eq_add_S, SEQ]. } + { by rewrite //= !eqseq_cons -IHjobso; + [rewrite andbA; f_equal | apply eq_add_S, SEQ]. } + } + rewrite /pr_eq (pr_joint_pred_eq _ _ _ (fun ω => ξf ω == b) xpredT); last first. + { by intros [ω n]; rewrite andbT; reflexivity. } + rewrite pr_xpredT Rmult_comm !Rmult_1_r. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + symmetry; rewrite Rmult_assoc Rmult_comm Rmult_assoc; apply Rmult_eq_compat_l; symmetry. + apply: eq_tr4; first apply (IND csN b). + { apply pr_eq_pred => ω; rewrite !unfold_in //=; unfold csN in *. + do 2 f_equal; clear IND H_jrep_notin_jobs csN csE; move: cs SEQ. + induction jobs as [| jo jobso]; first by done. + intros []; [by done | intros; simpl]. + (have [/eqP EQa | NEQa] := boolP (j_rep == jo)); + by simpl; erewrite IHjobso; [reflexivity | apply eq_add_S, SEQ]. + } + { rewrite Rmult_comm; apply Rmult_eq_compat_r. + rewrite /pr_eq; apply pr_eq_pred => ω; rewrite !unfold_in //=; unfold csN in *. + do 2 f_equal; clear IND H_jrep_notin_jobs csN csE; move: cs SEQ. + induction jobs as [| jo jobso]; first by done. + intros []; [by done | intros; simpl]. + (have [/eqP EQa | NEQa] := boolP (j_rep == jo)); + by simpl; erewrite IHjobso; [reflexivity | apply eq_add_S, SEQ]. + } + Qed. + + End IndependentArrSeq. + + Section IndependentArrSeqPartition. + + Variable jobs : seq Job. + Hypothesis H_jrep_notin_jobs : j_rep \notin jobs. + + Lemma transformation_respects_pET_indep_arr_seq_eq_part_step : + (forall (ξpart := @partition_on_ξ (Ω_of S) (μ_of S) Job (𝓐_of S)) (ξ : I ξpart), + @indep2 _ _ _ (μ_of S) + {| rvar_fun := λ ω : Ω_of S, [seq 𝓒_of S j0 ω | j0 <- jobs] |} + {| rvar_fun := [eta ξpart◁{ξ}] |} + ) -> + forall (ξpart := @partition_on_ξ (Ω_of S') (μ_of S') Job (𝓐_of S')) (ξ : I ξpart), + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω : Ω_of S', [seq 𝓒_of S' j0 ω | j0 <- jobs] |} + {| rvar_fun := [eta ξpart◁{ξ}] |}. + Proof. + intros IND *; apply transformation_respects_pET_indep_arr_seq_eq_step => //. + rename ξ into ξs'. + have [ξs EQ] := transformation_preserves_arr_seq _ _ ξs'; simpl in EQ. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + specialize (IND ξs); destruct ξs' as [ξ' INξ'], ξs as [ξ INξ]. + intros ? ?; apply: eq_tr4; first by apply IND. + { apply pr_eq_pred => ω; rewrite !unfold_in. + f_equal => //=; unfold ξ_fix; do 2 f_equal. + simpl in EQ; clear INξ' IND INξ. + apply (@FunctionalExtensionality.functional_extensionality _ _ ξ' ξ). + by intros; symmetry; apply EQ. + } + { f_equal; apply pr_eq_pred => ω; rewrite !unfold_in. + f_equal => //=; unfold ξ_fix; f_equal. + apply (@FunctionalExtensionality.functional_extensionality _ _ ξ' ξ). + by intros; symmetry; apply EQ. + } + Qed. + + Lemma transformation_respects_pET_indep_arr_seq_remove_part_step : + (forall (ξpart := @partition_on_ξ (Ω_of S) (μ_of S) Job (𝓐_of S)) (ξ : I ξpart), + @indep2 _ _ _ (μ_of S) + {| rvar_fun := λ ω : Ω_of S, [seq 𝓒_of S j0 ω | j0 <- jobs & predC1 j0 j_rep] |} + {| rvar_fun := [eta ξpart◁{ξ}] |} + ) -> + forall (ξpart := @partition_on_ξ (Ω_of S') (μ_of S') Job (𝓐_of S')) (ξ : I ξpart), + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω : Ω_of S', [seq 𝓒_of S' j0 ω | j0 <- jobs] |} + {| rvar_fun := [eta ξpart◁{ξ}] |}. + Proof. + intros IND *; apply transformation_respects_pET_indep_arr_seq_remove_step => //. + rename ξ into ξs'. + have [ξs EQ] := transformation_preserves_arr_seq _ _ ξs'; simpl in EQ. + destruct S as [Ω μ A C]. + destruct pWCET_pmf as [pWCET nonneg sum1]; simpl in *. + set (μ_tsk := {| pmf := pWCET (job_task j_rep); + pmf_pos := nonneg (job_task j_rep); + pmf_sum1 := sum1 (job_task j_rep) |}) in *. + specialize (IND ξs); destruct ξs' as [ξ' INξ'], ξs as [ξ INξ]. + intros ? ?; apply: eq_tr4; first by apply IND. + { apply pr_eq_pred => ω; rewrite !unfold_in. + f_equal => //=; unfold ξ_fix; do 2 f_equal. + simpl in EQ; clear INξ' IND INξ. + apply (@FunctionalExtensionality.functional_extensionality _ _ ξ' ξ). + by intros; symmetry; apply EQ. + } + { f_equal; apply pr_eq_pred => ω; rewrite !unfold_in. + f_equal => //=; unfold ξ_fix; f_equal. + apply (@FunctionalExtensionality.functional_extensionality _ _ ξ' ξ). + by intros; symmetry; apply EQ. + } + Qed. + + End IndependentArrSeqPartition. + + End Step1. + + Section Step2. + + Variable jobs_rep : seq Job. + Hypothesis H_jrep_notin_jobs : uniq jobs_rep. + + Variable S : @system Job. + Let S' : system := foldr replace_job_pET S jobs_rep. + + Let ξpart := @partition_on_ξ (Ω_of S') (μ_of S') Job (𝓐_of S'). + Variable (ξ : I ξpart). + + Lemma replaced_pETs_are_independent_from_arr_seq_partition_steps : + forall (jobs : seq Job), + (forall j, j \in jobs -> j \in jobs_rep) -> + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω : Ω_of S', [seq 𝓒_of S' j0 ω | j0 <- jobs] |} + {| rvar_fun := [eta ξpart◁{ξ}] |}. + Proof. + induction jobs_rep as [| j_rep jobs_repo]; destruct S as [Ω μ 𝓐 𝓒]. + { intros; destruct jobs. + { intros [] ?; simpl. + { by symmetry; rewrite /pr_eq //= pr_xpredT_ext // Rmult_1_l. } + { by rewrite //= pr_xpred0; symmetry; apply Rmult_eq_0_compat_r, pr_zero. } + } + { exfalso; specialize (H s); feed H; last by done. + by rewrite in_cons eq_refl orTb. + } + } + { intros * SUB; set (ξe := {| rvar_fun := [eta ξpart◁{ξ}] |}). + have [IN|NIN] := boolP (j_rep \in jobs). + { apply transformation_respects_pET_indep_arr_seq_remove_part_step => //; intros. + apply IHjobs_repo; first by move: H_jrep_notin_jobs => /andP [_ T]. + intros *; rewrite mem_filter /predC1. + move => /andP [NEQ INj]; specialize (SUB _ INj). + move: SUB; rewrite in_cons. + move => /orP [/eqP EQ| INr] => //; subst. + by simpl in NEQ; rewrite eq_refl in NEQ. + } + { apply transformation_respects_pET_indep_arr_seq_eq_part_step => //; intros. + apply IHjobs_repo; first by move: H_jrep_notin_jobs => /andP [_ T]. + intros; specialize (SUB _ H). + move: SUB; rewrite in_cons. + move => /orP [/eqP EQ| INr] => //. + by subst; move: NIN; rewrite H. + } + } + Qed. + + End Step2. + + Section Step3. + + Variable S : @system Job. + Let S' := replace_all_pETs S. + + Let ξpart := @partition_on_ξ (Ω_of S') (μ_of S') Job (𝓐_of S'). + Variable (ξ : I ξpart). + Variable (ρ : PosProb (μ_of S') (ξpart◁{ξ})). + + Lemma replaced_pETs_are_independent_from_arr_seq_partition : + ∀ (jobs : seq Job), + @indep2 _ _ _ (μ_of S') + {| rvar_fun := λ ω, [seq 𝓒_of S' j0 ω | j0 <- jobs] |} + {| rvar_fun := [eta ξpart◁{ξ}] |}. + Proof. + intros. + apply replaced_pETs_are_independent_from_arr_seq_partition_steps. + apply index_enum_uniq. + by intros; apply mem_index_enum. + Qed. + + Lemma replaced_pETs_are_cond_independent : + @independent + _ _ (restrict (μ_of S') (ξpart◁{ξ})) + [seq mkRvar _ (𝓒_of S' j) | j <- index_enum Job]. + Proof. + intros ? LEN. + rewrite -!seq_ext.size_legacy size_map in LEN. + rewrite fold_prob_to_cond_prob pr_cond_indep2; last first. + { eapply indep2_fn_extl with + (X1 := {| rvar_fun := λ ω : Ω_of S', [seq 𝓒_of S' j0 ω | j0 <- index_enum Job] |}) + (f := fun X1 => fold_right andb true [seq Xb.1 == Xb.2 | Xb <- seq.zip X1 lb]). + { by intros; rewrite //= zip_map_rvar_eq; reflexivity. } + { by apply replaced_pETs_are_independent_from_arr_seq_partition. } + } + apply: eq_tr4. + { by apply replaced_pETs_are_independent; rewrite -!seq_ext.size_legacy size_map; apply LEN. } + { apply pr_eq_pred => ω; rewrite !unfold_in. + by f_equal; rewrite !zip_map_rvar_eq; f_equal. + } + { rewrite !zip_map_pr_eq !foldr_big !big_map; apply eq_big; first by done. + intros [j t] _; rewrite /pr_eq fold_prob_to_cond_prob pr_cond_indep2; first by reflexivity. + eapply indep2_fn_extl with + (X1 := {| rvar_fun := λ ω : Ω_of S', [seq 𝓒_of S' j0 ω | j0 <- [::j]] |}) + (f := fun X1 => fold_right andb true [seq Xb.1 == Xb.2 | Xb <- seq.zip X1 [::t]]). + { by intros; rewrite //= andbT; reflexivity. } + { by apply replaced_pETs_are_independent_from_arr_seq_partition. } + } + Qed. + + Lemma replaced_cond_pETs_bounded_by_pWCETs : + ∀ (j : Job) (tsk : Task), + job_of_task tsk j → + mkRvar (restrict (μ_of S') (ξpart◁{ξ})) [eta odflt0 (𝓒_of S' j)] ⪯ to_distrib pWCET_pmf tsk. + Proof. + intros; intros ?. + rewrite fold_prob_to_cond_prob. + rewrite pr_cond_indep2; last first. + { apply indep2_fn_extl with (X1 := {| rvar_fun := [eta odflt0 (𝓒_of S' j)] |}) (f := fun X1 => X1 <= h). + { by intros; reflexivity. } + apply indep2_fn_extl with (X1 := 𝓒_of S' j) (f := odflt 0). + { by intros; reflexivity. } + apply indep2_fn_extl with + (X1 := {| rvar_fun := λ ω : Ω_of S', [seq 𝓒_of S' j0 ω | j0 <- [::j]] |}) + (f := head None). + { by intros; reflexivity. } + apply replaced_pETs_are_independent_from_arr_seq_partition. + } + by eapply Rge_trans, replaced_pETs_bounded_by_pWCETs, H; apply Rge_refl. + Qed. + + End Step3. + +End TransformationEnsuresCostsIndependentFromArrivals. diff --git a/rt/analysis/work_bound.v b/rt/analysis/work_bound.v index 975d34e..fb98d26 100644 --- a/rt/analysis/work_bound.v +++ b/rt/analysis/work_bound.v @@ -33,9 +33,9 @@ Section PrTaskWorkloadBoundedNthCost. (** Assume that job costs are independent of the (prob.) arrival sequence. *) Let ξpart := partition_on_ξ μ : Ω_partition. - Hypothesis H_job_costs_independent_arr_seq : + Hypothesis job_costs_independent_arr_seq : let ξpart := partition_on_ξ μ : Ω_partition in - forall (ξ : I ξpart) `(!PosProb μ (ξpart◁{ξ})) (jobs : seq Job), + forall (ξ : I ξpart) `{!PosProb μ (ξpart◁{ξ})} (jobs : seq Job), indep2 (mkRvar μ (fun ω => [seq job_cost j ω | j <- jobs])) (mkRvar μ (fun ω => ξpart◁{ξ} ω)). @@ -61,7 +61,7 @@ Section PrTaskWorkloadBoundedNthCost. { by rewrite //= in IHjobs; rewrite //= !big_cons //= IHjobs. } } eapply indep2_fn_extl; first by intros; apply: EQ. - by apply H_job_costs_independent_arr_seq, PosProb0. + by apply job_costs_independent_arr_seq, PosProb0. Qed. diff --git a/util/seq.v b/util/seq.v new file mode 100644 index 0000000..09bdcaa --- /dev/null +++ b/util/seq.v @@ -0,0 +1,179 @@ +(* --------------------------- Reals and SSReflect -------------------------- *) +From mathcomp Require Export ssreflect ssrbool eqtype ssrnat seq. + +(* --------------------------------- Prosa ---------------------------------- *) +Require Export prosa.util.list. + +(* ---------------------------------- Main ---------------------------------- *) +Lemma seq_split_take_drop : + forall {X : eqType} (e : X) (xs : seq X), + (e \in xs) -> + xs = take (index e xs) xs ++ [:: e] ++ drop (index e xs).+1 xs. +Proof. + intros * IN. + induction xs; first by done. + simpl; destruct ( _ == _ ) eqn:EQ. + { by rewrite //= drop0; move: EQ => /eqP EQ; subst. } + { rewrite //= {1}IHxs //=. + by move: IN; rewrite in_cons eq_sym EQ orFb. } +Qed. + +Lemma seq_split : + forall {X : eqType} (e : X) (xs : seq X), + (e \in xs) -> + exists xs1 xs2, + xs = xs1 ++ [::e] ++ xs2 + /\ (e \notin xs1). +Proof. + intros * IN. + set (i := index e xs). + exists (take i xs), (drop i.+1 xs). + repeat split. + { by apply seq_split_take_drop. } + { apply/negP => INT; apply index_ltn in INT. + by rewrite ltnn in INT. + } +Qed. + +Lemma choose_superior_default_or_in_seq : + forall {X : eqType} (R : rel X) (a e : X) (ys : seq X), + foldr (choose_superior R) (Some a) ys = Some e -> + a = e \/ e \in ys. +Proof. + intros; induction ys. + { by inversion H; subst; left. } + { simpl in H. + destruct (foldr (choose_superior R) (Some a) ys) eqn:FLR. + { unfold choose_superior in H; destruct (R a0 s) eqn:REL. + { inversion H; subst; right. + by rewrite in_cons eq_refl orTb. } + { inversion H; subst; apply IHys in H. + by destruct H; [subst; left | right; rewrite in_cons H orbT]. + } + } + { by inversion H; subst; right; rewrite in_cons eq_refl orTb. } + } +Qed. + +Lemma foldr_choose_superior_not_none : + forall {X : eqType} (R : rel X) (e : X) (ys : seq X), + ~ foldr (choose_superior R) (Some e) ys = None. +Proof. + intros; induction ys; first by simpl. + simpl; intros ?; apply: IHys. + destruct (foldr (choose_superior R) (Some e) ys). + { by unfold choose_superior in H; destruct (R a s). } + { by done. } +Qed. + +Lemma foldr_choose_superior_in_seq : + forall {X : eqType} (R : rel X) (ys : seq X) (y e : X), + (y \in ys) -> + (R y e) -> + foldr (choose_superior R) (Some e) ys = Some e -> + e \in ys. +Proof. + intros * IN Rye FL. + have FF := seq_split _ _ IN. + destruct FF as [xs1 [xs2 [EQ NIN]]]. + subst; rewrite !foldr_cat in FL. + simpl in FL; clear IN. + destruct (foldr (choose_superior R) (Some e) xs2) eqn:EQ. + { simpl in FL; destruct (R y s) eqn: RR. + { eapply choose_superior_default_or_in_seq in FL; destruct FL as []; subst. + { by rewrite !mem_cat mem_seq1 eq_refl orbT. } + { by rewrite !mem_cat H. } + } + { apply choose_superior_default_or_in_seq in FL. + destruct FL as []; subst. + { by rewrite RR in Rye. } + { by rewrite !mem_cat H. } + } + } + { by eapply foldr_choose_superior_not_none in EQ. } +Qed. + +Lemma supremum_monotone_wrt_subset : + forall {X : eqType} (R : rel X) (e : X) (xs ys : seq X), + reflexive R -> + total R -> + transitive R -> + uniq ys -> + subseq xs ys -> + (e \in xs) -> + supremum R ys = Some e -> + supremum R xs = Some e. +Proof. + intros * REF TOT TR UNIQ SUB IN SUP. + have INy : e \in ys by apply: supremum_in; eassumption. + move: (seq_split e ys INy) => [ys1 [ys2 [EQ NINy]]]; subst ys. + have NR1 : forall y, y \in ys2 -> R e y. + { intros; apply supremum_spec with (y0 := y) in SUP => //. + by rewrite mem_cat mem_cat H !orbT. } + have NR2 : forall y, y \in ys1 -> ~~ R y e. + { intros; apply/negP => Rye; clear INy SUB IN. + rewrite /supremum !foldr_cat in SUP. + destruct (foldr (choose_superior R) None ys2) eqn:FLD2. + { have EQ : foldr (choose_superior R) (Some s) [:: e] = Some e. + { by rewrite //= NR1; [reflexivity | apply supremum_in in FLD2]. } + rewrite EQ in SUP; clear EQ FLD2. + eapply foldr_choose_superior_in_seq in SUP; eauto 1. + by rewrite SUP in NINy. + } + { eapply foldr_choose_superior_in_seq in SUP; eauto 1. + by rewrite SUP in NINy. + } + } + have L2: exists xs1 xs2, xs = xs1 ++ [::e] ++ xs2 /\ e \notin xs1. + { set (i := index e xs). + exists (take i xs), (drop i.+1 xs). + repeat split. + { by apply seq_split_take_drop. } + { apply/negP => INT; apply index_ltn in INT. + by rewrite ltnn in INT. + } + } + clear IN; move: L2 => [xs1 [xs2 [EQ NINx]]]; subst xs. + have L22: subseq xs1 ys1 /\ subseq xs2 ys2. + { apply/andP; erewrite <-uniq_subseq_pivot. + { by instantiate (1 := e); apply SUB. } + { by done. } + } + clear SUB; move: L22 => [SUB1 SUB2]. + have L3 : forall x : X, x \in xs1 -> ~~ R x e. + { by intros * IN; apply NR2; apply: mem_subseq; eauto 1. } + have L4 : forall x : X, x \in xs2 -> R e x. + { by intros * IN; apply NR1; apply: mem_subseq; eauto 1. } + rewrite /supremum foldr_cat foldr_cat. + have FLEQ: foldr (choose_superior R) (Some e) xs1 = Some e. + { clear SUB1 SUB2 NINy NINx. + induction xs1; first by done. + rewrite //= IHxs1. + { simpl. + have -> : R a e = false. + { apply/eqP; rewrite eqbF_neg; apply L3. + by rewrite in_cons eq_refl orTb. + } + reflexivity. + } + { by intros; apply L3; rewrite in_cons H orbT. } + } + destruct (foldr _ None _) eqn:FL3; last by apply FLEQ. + destruct (foldr _ (Some s) _) eqn:FLe. + { simpl in FLe. + rewrite L4 in FLe; last by apply: supremum_in; apply FL3. + inversion FLe; subst s0; clear FLe. + by apply FLEQ. + } + { by simpl in FLe; destruct (R e s). } +Qed. + +Lemma subseq_filter : + forall {X : eqType} (xs : seq X) (P1 P2 : pred X), + (forall x, x \in xs -> P1 x -> P2 x) -> + subseq [seq x <- xs | P1 x] [seq x <- xs | P2 x]. +Proof. + intros; rewrite subseq_filter; apply/andP; split. + { by apply/allP => x; rewrite mem_filter => /andP [Px INx]; apply H. } + { by apply filter_subseq. } +Qed. -- GitLab