Library prosa.analysis.facts.behavior.service

Service

In this file, we establish basic facts about the service received by jobs.
To begin with, we provide some simple but handy rewriting rules for service and service_during.
Section Composition.

Consider any job type and any processor state.
  Context {Job: JobType}.
  Context {PState: ProcessorState Job}.

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:
     t1 t2,
      t1 t2 service_during sched j t1 t2 = 0.

Conversely, if a job receives some service in some interval, then the interval is not empty.
  Corollary service_during_ge :
     t1 t2 k,
      service_during sched j t1 t2 > k
      t1 < t2.

Equally trivially, no job has received service prior to time zero.
  Corollary service0:
    service sched j 0 = 0.

Trivially, an interval consisting of one time unit is equivalent to service_at.
  Lemma service_during_instant:
     t,
      service_during sched j t t.+1 = service_at sched j t.

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:
     t1 t2 t3,
      t1 t2 t3
      (service_during sched j t1 t2) + (service_during sched j t2 t3)
      = service_during sched j t1 t3.

Since service is just a special case of service_during, the same holds for service.
  Lemma service_cat:
     t1 t2,
      t1 t2
      (service sched j t1) + (service_during sched j t1 t2)
      = service sched j t2.

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:
     t1 t2,
      t1 < t2
      (service_at sched j t1) + (service_during sched j t1.+1 t2)
      = service_during sched j t1 t2.

Symmetrically, we have the same for the end of the interval.
  Lemma service_during_last_plus_before:
     t1 t2,
      t1 t2
      (service_during sched j t1 t2) + (service_at sched j t2)
      = service_during sched j t1 t2.+1.

And hence also for service.
  Corollary service_last_plus_before:
     t,
      (service sched j t) + (service_at sched j t)
      = service sched j t.+1.

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.
As a common special case, we establish facts about schedules in which a job receives either 1 or 0 service units at all times.
Section UnitService.

Consider any job type and any processor state.
  Context {Job : JobType}.
  Context {PState : ProcessorState Job}.

Let's consider a unit-service 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:
     t, service_at sched j t 1.

... which implies that the instantaneous service always equals to 0 or 1.
  Corollary service_is_zero_or_one:
     t, service_at sched j t = 0 service_at sched j t = 1.

Next we prove that the cumulative service received by job j in any interval of length delta is at most delta.
Conversely, we prove that if the cumulative service received by job j in an interval of length delta is greater than or equal to ρ, then ρ delta.
  Lemma cumulative_service_ge_delta :
     t delta ρ,
      ρ service_during sched j t (t + delta)
      ρ delta.

  Section ServiceIsUnitGrowthFunction.

We show that the service received by any job j during any interval is a unit growth function...
    Lemma service_during_is_unit_growth_function :
       t0,
        unit_growth_function (service_during sched j t0).

... and restate the same observation in terms of service.
It follows that service_during does not skip over any values.
    Corollary exists_intermediate_service_during :
       t0 t1 t2 s,
        t0 t1 t2
        service_during sched j t0 t1 s < service_during sched j t0 t2
       t,
        t1 t < t2
        service_during sched j t0 t = s.

To restate this observation in terms of service, let s be any value less than the service received by job j by time t.
    Variable t : instant.
    Variable s : duration.
    Hypothesis H_less_than_s: s < service sched j t.

There necessarily exists an earlier time t' where job j had s units of service.
    Corollary exists_intermediate_service :
       t',
        t' < t
        service sched j t' = s.

  End ServiceIsUnitGrowthFunction.

End UnitService.

In this section we prove a lemma about the service received by a job in a fully-consuming processor schedule.
Consider any type of tasks ...
  Context {Task : TaskType}.

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

Consider any kind of fully-supply-consuming processor state model.
Consider any arrival sequence ...
  Variable arr_seq : arrival_sequence Job.

... and any schedule of this arrival sequence.
  Variable sched : schedule PState.

We show that, given that the processor provides supply at a time instant t, the fact that a job j is scheduled at time t implies that the job receives service at time t. Intuitively, this lemma states that "inside a supply" the model is equivalent to the ideal uniprocessor model.
  Lemma ideal_progress_inside_supplies :
     j t,
      has_supply sched t
      scheduled_at sched j t
      receives_service_at sched j t.

End FullyConsumingProcessor.

We establish a basic fact about the monotonicity of service.
Section Monotonicity.

Consider any job type and any processor model.
  Context {Job: JobType}.
  Context {PState: ProcessorState Job}.

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:
     t1 t2,
      t1 t2
      service sched j t1 service sched j t2.

End Monotonicity.

In the following, we establish a collection of facts relating service with predicates scheduled_in and scheduled_at.
Consider any job type and any processor model.
  Context {Job: JobType}.
  Context {PState: ProcessorState Job}.

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 in a given processor state cannot possibly receive service in that state.
  Lemma service_in_implies_scheduled_in :
     s,
      ~~ scheduled_in j s service_in j s = 0.

In particular, it cannot receive service at any given time.
  Corollary not_scheduled_implies_no_service:
     t,
      ~~ scheduled_at sched j t service_at sched j t = 0.

Similarly, if a job is not scheduled during an interval, then it does not receive any service in that interval.
  Lemma not_scheduled_during_implies_zero_service:
     t1 t2,
      ( t, t1 t < t2 ~~ scheduled_at sched j t)
      service_during sched j t1 t2 = 0.

Conversely, if the job's instantaneous received service is positive, then it must be scheduled.
  Lemma service_at_implies_scheduled_at :
     t,
      service_at sched j t > 0 scheduled_at sched j t.

Thus, if the cumulative amount of service changes, then it must be scheduled, too.
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 :
     t1 t2,
      service_during sched j t1 t2 > 0
      
       t,
        t1 t < t2
        service_at sched j t > 0.

Thus, any job that receives some service during an interval must be scheduled at some point during the interval...
  Corollary cumulative_service_implies_scheduled :
     t1 t2,
      service_during sched j t1 t2 > 0
       t,
        t1 t < t2
        scheduled_at sched j t.

...which implies that any job with positive cumulative service must have been scheduled at some point.
We can further strengthen service_during_service_at to yield the earliest point in time at which a job receives service in an interval...
  Corollary service_during_service_at_earliest :
     t1 t2,
      service_during sched j t1 t2 > 0
       t,
        t1 t < t2
         service_at sched j t > 0
         service_during sched j t1 t = 0.

... and make a similar observation about the same point in time w.r.t. scheduled_at.
  Corollary service_during_scheduled_at_earliest :
     t1 t2,
      service_during sched j t1 t2 > 0
       t,
        t1 t < t2
         scheduled_at sched j t
         service_during sched j t1 t = 0.

If we can assume that a scheduled job always receives service, then we can further relate above observations to scheduled_at.
  Section GuaranteedService.

Assume j always receives some positive service.
In other words, not being scheduled is equivalent to receiving zero service.
    Lemma no_service_not_scheduled:
       t,
        ~~ scheduled_at sched j t service_at sched j t = 0.

Then, if a job does not receive any service during an interval, it is not scheduled.
    Lemma no_service_during_implies_not_scheduled:
       t1 t2,
        service_during sched j t1 t2 = 0
         t,
          t1 t < t2 ~~ scheduled_at sched j t.

If a job is scheduled at some point in an interval, it receives positive cumulative service during the interval...
    Lemma scheduled_implies_cumulative_service:
       t1 t2,
        ( t,
            t1 t < t2
            scheduled_at sched j t)
        service_during sched j t1 t2 > 0.

...which again applies to total service, too.
    Corollary scheduled_implies_nonzero_service:
       t,
        ( t',
            t' < t
            scheduled_at sched j t')
        service sched j t > 0.

  End GuaranteedService.

Furthermore, if we know that jobs are not released early, then we can narrow the interval during which they must have been scheduled.
  Section AfterArrival.

    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:
       t,
        service sched j t > 0
         t', (job_arrival j t' < t scheduled_at sched j t').

    Lemma not_scheduled_before_arrival:
       t, t < job_arrival j ~~ scheduled_at sched j t.

We show that job j does not receive service at any time t prior to its arrival.
    Lemma service_before_job_arrival_zero:
       t,
        t < job_arrival j
        service_at sched j t = 0.

Note that the same property applies to the cumulative service.
    Lemma cumulative_service_before_job_arrival_zero :
       t1 t2 : instant,
        t2 job_arrival j
        service_during sched j t1 t2 = 0.

Hence, one can ignore the service received by a job before its arrival time...
    Lemma ignore_service_before_arrival:
       t1 t2,
        t1 job_arrival j
        t2 job_arrival j
        service_during sched j t1 t2 = service_during sched j (job_arrival j) t2.

... which we can also state in terms of cumulative service.
    Corollary no_service_before_arrival:
       t,
        t job_arrival j service sched j t = 0.

  End AfterArrival.

In this section, we prove some lemmas about time instants with same service.
  Section TimesWithSameService.

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)...
...which of course implies that it does not receive service at any point, either.
    Lemma constant_service_implies_not_scheduled:
       t,
        t1 t < t2 service_at sched j t = 0.

We show that job j receives service at some point t < t1 iff j receives service at some point t' < t2.
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.
We show that job j is scheduled at some point t < t1 iff j is scheduled at some point t' < t2.
In this section we prove a few auxiliary lemmas about the service received by a job.
Section GenericProcessor.

Consider any type of jobs.
  Context {Job : JobType}.
  Context `{JobArrival Job}.
  Context `{JobCost Job}.

Consider any kind of processor state model.
  Context `{PState : ProcessorState Job}.

Consider any valid arrival sequence with consistent arrivals ...
... and any schedule of this arrival sequence ...
... where jobs do not execute before their arrival or after completion.
If a job j receives service at time t, then j is in the set of served jobs at time t ...
... and vice versa, if j is in the set of jobs receiving service at time t, then j receives service at time t.
If the processor is idle at time t, then no job receives service at time t.
  Lemma no_service_received_when_idle :
     j t,
      is_idle arr_seq sched t
      ~~ receives_service_at sched j t.

Next, if a job j receives service at time t, then the processor has supply at time t.
  Lemma receives_service_implies_has_supply :
     j t,
      receives_service_at sched j t
      has_supply sched t.

Similarly, if a job j receives service at time t, then time t is not a blackout time.
  Lemma no_blackout_when_service_received :
     j t,
      receives_service_at sched j t
      ~~ is_blackout sched t.

Finally, if time t is a blackout time, then no job receives service at time t.
  Lemma no_service_during_blackout :
     j t,
      is_blackout sched t
      service_at sched j t = 0.

End GenericProcessor.

In this section we prove a lemma about the service received by a job in a uniprocessor schedule.
Section UniProcessor.

Consider any type of jobs.
  Context {Job : JobType}.

Consider any kind of uniprocessor state model.
Consider any schedule.
  Variable sched : schedule PState.

If two jobs j1 and j2 receive service at the same instant then j1 is equal to j2.
  Lemma only_one_job_receives_service_at_uni :
     j1 j2 t,
      receives_service_at sched j1 t
      receives_service_at sched j2 t
      j1 = j2.

End UniProcessor.

Incremental Service in Unit-Service Schedules

In unit-service schedules, any job gains at most one unit of service at any time. Hence, no job "skips" an service values, which we note with the lemma incremental_service_during below.
Consider any job type, ...
  Context {Job : JobType}.
  Context `{JobArrival Job}.
  Context `{JobCost Job}.

... any arrival sequence, ...
  Variable arr_seq : arrival_sequence Job.

... and any unit-service schedule of this arrival sequence.
  Context {PState : ProcessorState Job}.
  Variable sched : schedule PState.
  Hypothesis H_unit_service: unit_service_proc_model PState.

We prove that if in some time interval [t1,t2) a job j receives k units of service, then there exists a time instant t ∈ [t1,t2) such that j is scheduled at time t and service of job j within interval [t1,t) is equal to k.
  Lemma incremental_service_during :
     j t1 t2 k,
      service_during sched j t1 t2 > k
       t, t1 t < t2 scheduled_at sched j t service_during sched j t1 t = k.

An implication of the above lemma is that for any job j that has k units of service at time t and more than k units of service at time t', there exists a time instant st such that t st < t' and the job is scheduled but still has k units of service.
  Lemma kth_scheduling_time :
     j t t' k,
      service sched j t = k
      k < service sched j t'
       st,
        t st < t'
         service sched j st = k
         scheduled_at sched j st.
End IncrementalService.

Section ServiceInTwoSchedules.

Consider any job type and any processor model.
  Context {Job: JobType}.
  Context {PState: ProcessorState Job}.

Consider any two given schedules...
  Variable sched1 sched2: schedule PState.

Given an interval in which the schedules provide the same service to a job at each instant, we can prove that the cumulative service received during the interval has to be the same.
Consider two time instants...
    Variable t1 t2 : instant.

...and a given job that is to be scheduled.
    Variable j: Job.

Assume that, in any instant between t1 and t2 the service provided to j from the two schedules is the same.
    Hypothesis H_sched1_sched2_same_service_at:
       t, t1 t < t2
           service_at sched1 j t = service_at sched2 j t.

It follows that the service provided during t1 and t2 is also the same.
We can leverage the previous lemma to conclude that two schedules that match in a given interval will also have the same cumulative service across the interval.
  Corollary equal_prefix_implies_same_service_during:
     t1 t2,
      ( t, t1 t < t2 sched1 t = sched2 t)
       j, service_during sched1 j t1 t2 = service_during sched2 j t1 t2.

For convenience, we restate the corollary also at the level of service for identical prefixes.
  Corollary identical_prefix_service:
     h,
      identical_prefix sched1 sched2 h
       j, service sched1 j h = service sched2 j h.

End ServiceInTwoSchedules.

We add some facts into the "Hint Database" basic_rt_facts, so Coq will be able to apply them automatically where needed.
Global Hint Resolve
       served_at_and_receives_service_consistent
  : basic_rt_facts.