From 7ba4060555b92a34a5889d21b1cfab6bc250452e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Brandenburg?= <bbb@mpi-sws.org>
Date: Sun, 12 May 2019 01:16:59 +0200
Subject: [PATCH] Port lemmas from model/schedule/uni/schedule.v

- port completed_implies_scheduled_before
- port lemmas on service prior to arrival
- port scheduled_implies_pending and greatly simplify the proof while at it
- port and simplify job_pending_at_arrival
- port cumulative_service_implies_scheduled and simplify proof of
  positive_service_implies_scheduled_before
- port service_is_a_step_function
---
 behavior/schedule/completion_facts.v |  76 +++++++++
 behavior/schedule/service_facts.v    | 225 ++++++++++++++++++++-------
 2 files changed, 246 insertions(+), 55 deletions(-)

diff --git a/behavior/schedule/completion_facts.v b/behavior/schedule/completion_facts.v
index 842ca3cf0..90a870927 100644
--- a/behavior/schedule/completion_facts.v
+++ b/behavior/schedule/completion_facts.v
@@ -191,6 +191,27 @@ Section ServiceAndCompletionFacts.
       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 +
@@ -212,3 +233,58 @@ Section ServiceAndCompletionFacts.
  Qed.
 
 End ServiceAndCompletionFacts.
+
+Section PositiveCost.
+  (** In this section, we establish facts that on jobs with non-zero costs that
+      must arrive to execute. *)
+
+  (* Consider any type of jobs with cost and arrival-time 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/behavior/schedule/service_facts.v b/behavior/schedule/service_facts.v
index ab6302550..030df1b17 100644
--- a/behavior/schedule/service_facts.v
+++ b/behavior/schedule/service_facts.v
@@ -4,51 +4,9 @@ From rt.util Require Import tactics step_function.
 (** In this file, we establish basic facts about the service received by
     jobs. *)
 
-
-Section UnitService.
-  (** To begin with, 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 unit-service 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.
-
-End UnitService.
-
 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: eqType}.
@@ -169,6 +127,85 @@ Section Composition.
 
 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 unit-service 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. *)
 
@@ -239,20 +276,40 @@ Section RelationToScheduled.
     apply: service_at_implies_scheduled_at.
   Qed.
 
-  (* Similarly, any job with positive cumulative service must have been
-     scheduled before. *)
-  Lemma positive_service_implies_scheduled_before:
+  (* Similarly, any job that receives some service during an interval must be
+     scheduled during at some point during the interval... *)
+  Lemma 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 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.
+      by apply: service_at_implies_scheduled_at => //.
+    - 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 => //.
+  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=> t.
-    elim: t => [|t IND SERVICE].
-    - rewrite service0 //.
-    - destruct (scheduled_at sched j t) eqn:SCHED.
-      * exists t; split; auto.
-      * move: SERVICE. rewrite -service_last_plus_before not_scheduled_implies_no_service; last by apply negbT; assumption. rewrite addn0.
-        move=> SERVICE. apply IND in SERVICE. inversion SERVICE as [t'' [t''t SCHED_AT]].
-        exists t''; split; auto.
+    move=> t2.
+    rewrite /service => NONZERO.
+    have EX_SCHED := cumulative_service_implies_scheduled 0 t2 NONZERO.
+    by inversion EX_SCHED as [t [TIMES SCHED_AT]]; exists t; split.
   Qed.
 
   Section AfterArrival.
@@ -280,6 +337,64 @@ Section RelationToScheduled.
         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 big_const_nat iter_addn mul0n addn0 //.
+      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.
 
 End RelationToScheduled.
-- 
GitLab