Library rt.restructuring.analysis.basic_facts.preemption.job.limited

Platform for Models with Limited Preemptions

In this section, we prove that instantiation of predicate job_preemptable to the model with limited preemptions indeed defines a valid preemption model.
Consider any type of tasks ...
  Context {Task : TaskType}.
  Context `{TaskCost Task}.

... and any type of jobs associated with these tasks.
  Context {Job : JobType}.
  Context `{JobTask Job Task}.
  Context `{JobArrival Job}.
  Context `{JobCost Job}.

In addition, assume the existence of a function that maps a job to the sequence of its preemption points.
  Context `{JobPreemptionPoints Job}.

Consider any arrival sequence.
  Variable arr_seq : arrival_sequence Job.

Next, consider any limited ideal uniprocessor schedule of this arrival sequence ...
...where jobs do not execute after their completion.
Next, we assume that preemption points are defined by the job-level model with limited preemptions.
First, we prove a few auxiliary lemmas.
  Section AuxiliaryLemmas.

Consider a job j.
    Variable j : Job.
    Hypothesis H_j_arrives : arrives_in arr_seq j.

Recall that 0 is a preemption point.
Using the fact that job_preemption_points is a non-decreasing sequence, we prove that the first element of job_preemption_points is 0.
    Lemma zero_is_first_element: first0 (job_preemption_points j) = 0.
    Proof.
      have F := zero_in_preemption_points.
      destruct H_valid_limited_preemptions_job_model as [_ [_ C]]; specialize (C j H_j_arrives).
        by apply nondec_seq_zero_first.
    Qed.

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_valid_limited_preemptions_job_model ⇒ [BEG [END _]].
      apply/negPn/negP; rewrite -eqn0Ngt; intros CONTR; rewrite size_eq0 in CONTR.
      specialize (BEG j H_j_arrives).
        by rewrite /beginning_of_execution_in_preemption_points (eqbool_to_eqprop CONTR) in BEG.
    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_valid_limited_preemptions_job_model ⇒ [BEG [END _]].
      move: (END _ H_j_arrives) ⇒ EQ.
      rewrite -EQ; clear EQ.
      rewrite /last0 -nth_last.
      apply/(nthP 0).
       ((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 sequence of nonpreemptive points of a job with poisitive cost contains at least 2 points.
    Corollary number_of_preemption_points_at_least_two:
      job_cost_positive j
      2 size (job_preemption_points j).
    Proof.
      intros POS.
      move: H_valid_limited_preemptions_job_model ⇒ [BEG [END _]].
      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 EQ|EQ]]; last by done.
      - by rewrite EQ; apply zero_in_preemption_points.
      - by rewrite EQ; apply job_cost_in_nonpreemptive_points.
    Qed.

Next we prove that "antidensity" property (from preemption.util file) holds for job_preemption_point j.
    Lemma antidensity_of_preemption_points:
       (ρ : work),
        ρ job_cost j
        ~~ (ρ \in job_preemption_points j)
        first0 (job_preemption_points j) ρ < last0 (job_preemption_points j).
    Proof.
      intros ρ LE NotIN.
      move: H_valid_limited_preemptions_job_model ⇒ [BEG [END NDEC]].
      apply/andP; split.
      - by rewrite zero_is_first_element.
      - rewrite 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 ⇒ /negP NIN; apply: NIN.
          by apply job_cost_in_nonpreemptive_points.
    Qed.

We also prove that any work that doesn't belong to preemption points of job j is placed strictly between two neighboring preemption points.
    Lemma work_belongs_to_some_nonpreemptive_segment:
       (ρ : work),
        ρ job_cost j
        ~~ (ρ \in job_preemption_points j)
         n,
          n.+1 < size (job_preemption_points j)
          nth 0 (job_preemption_points j) n < ρ < nth 0 (job_preemption_points j) n.+1.
    Proof.
      intros ρ LE NotIN.
      case: (posnP (job_cost j)) ⇒ [ZERO|POS].
      { exfalso; move: NotIN ⇒ /negP NIN; apply: NIN.
        move: LE. rewrite ZERO leqn0; move ⇒ /eqP →.
          by apply zero_in_preemption_points. }
      move: (belonging_to_segment_of_seq_is_total
               (job_preemption_points j) ρ (number_of_preemption_points_at_least_two POS)
               (antidensity_of_preemption_points _ LE NotIN)) ⇒ [n [SIZE2 /andP [N1 N2]]].
       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.
      rewrite -EQ; clear EQ.
      rewrite mem_nth //.
        by apply ltnW.
    Qed.

Recall that file job.parameters also defines notion of preemption poins. And note that job.parameter.job_preemption_points cannot have a duplicating preemption points. Therefore, we need additional lemmas to relate job.parameter.job_preemption_points and limited.job_preemption_points].
First we show that the length of the last non-preemptive segment of job.parameter.job_preemption_points is equal to the length of the last non-empty non-preemptive segment of limited.job_preemption_points.
    Lemma job_parameters_last_np_to_job_limited:
        last0 (distances (parameter.job_preemption_points j)) =
        last0 (filter (fun x ⇒ 0 < x) (distances (job_preemption_points j))).
    Proof.
      destruct H_valid_limited_preemptions_job_model as [A1 [A2 A3]].
      unfold parameter.job_preemption_points, job_preemptable, limited_preemptions_model.
      intros; rewrite distances_iota_filtered; eauto.
      rewrite -A2 //.
        by intros; apply last_is_max_in_nondecreasing_seq; eauto 2.
    Qed.

Next we show that the length of the max non-preemptive segment of job.parameter.job_preemption_points is equal to the length of the max non-preemptive segment of limited.job_preemption_points.
    Lemma job_parameters_max_np_to_job_limited:
      max0 (distances (parameter.job_preemption_points j)) =
      max0 (distances (job_preemption_points j)).
    Proof.
      destruct H_valid_limited_preemptions_job_model as [A1 [A2 A3]].
      unfold parameter.job_preemption_points, job_preemptable, limited_preemptions_model.
      intros; rewrite distances_iota_filtered; eauto 2.
      rewrite max0_rem0 //.
      rewrite -A2 //.
        by intros; apply last_is_max_in_nondecreasing_seq; eauto 2.
    Qed.

  End AuxiliaryLemmas.

We prove that the fixed_preemption_point_model function defines a valid preemption model.
  Lemma valid_fixed_preemption_points_model_lemma:
    valid_preemption_model arr_seq sched.
  Proof.
    intros j ARR; repeat split.
    { by apply zero_in_preemption_points. }
    { by apply job_cost_in_nonpreemptive_points. }
    { by movet NPP; apply H_valid_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.
        rewrite scheduled_at_def in NSCHED.
          by rewrite eqb0. }
      rewrite -[job_preemptable _ _]Bool.negb_involutive.
      apply/negP; intros CONTR.
      move: NSCHED ⇒ /negP NSCHED; apply: NSCHED.
      apply H_valid_schedule_with_limited_preemptions; first by done.
        by rewrite SERV.
    }
  Qed.

End ModelWithLimitedPreemptions.
Hint Resolve valid_fixed_preemption_points_model_lemma : basic_facts.