From e122dbb1d67b6e02adeb6a065c03d74207035ff1 Mon Sep 17 00:00:00 2001
From: Marco Maida <mmaida@mpi-sws.org>
Date: Mon, 9 May 2022 10:04:58 +0000
Subject: [PATCH] introduce "greedy" concrete arrival sequence

This commit defines and adds facts about a concrete arrival sequence in
which tasks release jobs "as quickly as possible" as allowed by their
respective arrival-curve constraints. This maximal arrival sequence is
used in POET to generate assumption-less certificates.
---
 .../definitions/maximal_arrival_sequence.v    |  88 ++++++
 .../facts/maximal_arrival_sequence.v          | 266 ++++++++++++++++++
 2 files changed, 354 insertions(+)
 create mode 100644 implementation/definitions/maximal_arrival_sequence.v
 create mode 100644 implementation/facts/maximal_arrival_sequence.v

diff --git a/implementation/definitions/maximal_arrival_sequence.v b/implementation/definitions/maximal_arrival_sequence.v
new file mode 100644
index 000000000..c46090c50
--- /dev/null
+++ b/implementation/definitions/maximal_arrival_sequence.v
@@ -0,0 +1,88 @@
+Require Export prosa.model.task.arrival.curves.
+Require Export prosa.util.supremum.
+
+(** * A Maximal Arrival Sequence *)
+
+(** In this section, we propose a concrete instantiation of an arrival sequence.
+    Given an arbitrary arrival curve, the defined arrival sequence tries to
+    generate as many jobs as possible at any time instant by adopting a greedy
+    strategy: at each time [t], the arrival sequence contains the maximum possible
+    number of jobs that does not violate the given arrival curve's constraints. *)
+Section MaximalArrivalSequence.
+
+  (** 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}.
+
+  (** Let [max_arrivals] denote any function that takes a task and an interval length
+      and returns the associated number of job arrivals of the task. *)
+  Context `{MaxArrivals Task}.
+
+  (** In this section, we define a procedure that computes the maximal number of
+      jobs that can be released at a given instant without violating the
+      corresponding arrival curve. *)
+  Section NumberOfJobs.
+
+    (** Let [tsk] be any task. *)
+    Variable tsk : Task.
+
+    (** First, we introduce a function that computes the sum of all elements in
+        a given list's suffix of length [n]. *)
+    Definition suffix_sum xs n := \sum_(size xs - n <= t < size xs) nth 0 xs t.
+
+    (** Let the arrival prefix [arr_prefix] be a sequence of natural numbers,
+        where [nth xs t] denotes the number of jobs that arrive at time [t].
+        Then, given an arrival curve [max_arrivals] and an arrival prefix
+        [arr_prefix], we define a function that computes the number of jobs that
+        can be additionally released without violating the arrival curve.
+
+        The high-level idea is as follows. Let us assume that the length of the
+        arrival prefix is [Δ]. To preserve the sub-additive property, one needs
+        to go through all suffixes of the arrival prefix and pick the
+        minimum. *)
+    Definition jobs_remaining (arr_prefix : seq nat) :=
+      supremum leq [seq (max_arrivals tsk Δ.+1 - suffix_sum arr_prefix Δ) | Δ <- iota 0 (size arr_prefix).+1].
+
+    (** Further, we define the function [next_max_arrival] to handle a special
+        case: when the arrival prefix is empty, the function returns the value
+        of the arrival curve with a window length of [1]. Otherwise, it returns
+        the number the number of jobs that can additionally be generated.  *)
+    Definition next_max_arrival (arr_prefix : seq nat) :=
+      match jobs_remaining arr_prefix with
+      | None => max_arrivals tsk 1
+      | Some n => n
+      end.
+
+    (** Next, we define a function that extends by one a given arrival prefix... *)
+    Definition extend_arrival_prefix (arr_prefix : seq nat) :=
+      arr_prefix ++ [:: next_max_arrival arr_prefix ].
+
+    (** ... and a function that generates a maximal arrival prefix
+        of size [t], starting from an empty arrival prefix. *)
+    Definition maximal_arrival_prefix (t : nat) :=
+      iter t.+1 extend_arrival_prefix [::].
+
+    (** Finally, we define a function that returns the maximal number
+        of jobs that can be released at time [t]; this definition
+        assumes that at each time instant prior to time [t] the maximal
+        number of jobs were released. *)
+    Definition max_arrivals_at t := nth 0 (maximal_arrival_prefix t) t.
+
+  End NumberOfJobs.
+
+  (** Consider a function that generates [n] concrete jobs of
+      the given task at the given time instant. *)
+  Variable generate_jobs_at : Task -> nat -> instant -> seq Job.
+
+  (** The maximal arrival sequence of task set [ts] at time [t] is a
+      concatenation of sequences of generated jobs for each task. *)
+  Definition concrete_arrival_sequence (ts : seq Task) (t : instant) :=
+    \cat_(tsk <- ts) generate_jobs_at tsk (max_arrivals_at tsk t) t.
+
+End MaximalArrivalSequence.
diff --git a/implementation/facts/maximal_arrival_sequence.v b/implementation/facts/maximal_arrival_sequence.v
new file mode 100644
index 000000000..73856ca88
--- /dev/null
+++ b/implementation/facts/maximal_arrival_sequence.v
@@ -0,0 +1,266 @@
+Require Export prosa.analysis.facts.model.task_arrivals.
+Require Export prosa.implementation.definitions.maximal_arrival_sequence.
+
+(** Recall that, given an arrival curve [max_arrivals] and a
+    job-generating function [generate_jobs_at], the function
+    [concrete_arrival_sequence] generates an arrival sequence. In this
+    section, we prove a few properties of this function. *)
+Section MaximalArrivalSequence.
+
+  (** 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}.
+
+  (** Consider a task set [ts] with non-duplicate tasks. *)
+  Variable ts : seq Task.
+  Hypothesis H_ts_uniq : uniq ts.
+
+  (** Let [max_arrivals] be a family of valid arrival curves, i.e.,
+      for any task [tsk] in [ts], [max_arrival tsk] is (1) an arrival
+      bound of [tsk], and (2) it is a monotonic function that equals [0]
+      for the empty interval [delta = 0]. *)
+  Context `{MaxArrivals Task}.
+  Hypothesis H_valid_arrival_curve : valid_taskset_arrival_curve ts max_arrivals.
+
+  (** Further assume we are given a function that generates the required number of
+      jobs of a given task at a given instant of time. *)
+  Variable generate_jobs_at : Task -> nat -> instant -> seq Job.
+
+  (** First, we assume that [generate_jobs_at tsk n t] generates [n] jobs. *)
+  Hypothesis H_job_generation_valid_number:
+    forall (tsk : Task) (n : nat) (t : instant), tsk \in ts -> size (generate_jobs_at tsk n t) = n.
+
+  (** Second, we assume that [generate_jobs_at tsk n t] generates jobs of task
+      [tsk] that arrive at time [t]. *)
+  Hypothesis H_job_generation_valid_jobs:
+    forall (tsk : Task) (n : nat) (t : instant) (j : Job),
+      (j \in generate_jobs_at tsk n t) ->
+      job_task j = tsk
+      /\ job_arrival j = t
+      /\ job_cost j <= task_cost tsk.
+
+  (** Finally, we assume that all jobs generated by [generate_jobs_at] are unique. *)
+  Hypothesis H_jobs_unique:
+    forall (t1 t2 : instant),
+      uniq (arrivals_between (concrete_arrival_sequence generate_jobs_at ts) t1 t2).
+
+  (** Assuming such a well-behaved "constructor" [generate_jobs_at], we prove a
+      few validity claims about an arrival sequence generated by
+      [concrete_arrival_sequence]. *)
+  Section ValidityClaims.
+
+    (** We start by showing that the obtained arrival sequence is a set. *)
+    Lemma arr_seq_is_a_set :
+      arrival_sequence_uniq (concrete_arrival_sequence generate_jobs_at ts).
+    Proof.
+      move=> t.
+      move: (H_jobs_unique t t.+1).
+      by rewrite /arrivals_between big_nat1.
+    Qed.
+
+    (** Next, we show that all jobs in the arrival sequence come from [ts]. *)
+    Lemma concrete_all_jobs_from_taskset :
+      all_jobs_from_taskset (concrete_arrival_sequence generate_jobs_at ts) ts.
+    Proof.
+      move=> j [t /mem_bigcat_exists [tsk [TSK_IN IN]]].
+      move: (H_job_generation_valid_jobs tsk _ _ _ IN) => [JOB_TASK _].
+      by rewrite JOB_TASK.
+    Qed.
+
+    (** Further, we note that the jobs in the arrival sequence have consistent
+        arrival times. *)
+    Lemma arrival_times_are_consistent :
+      consistent_arrival_times (concrete_arrival_sequence generate_jobs_at ts).
+    Proof.
+      move=> j t /mem_bigcat_exists [tsk [TSK_IN IN]].
+      by move: (H_job_generation_valid_jobs tsk _ _ _ IN) => [_ [JOB_ARR _]].
+    Qed.
+
+    (** Lastly, we observe that the jobs in the arrival sequence have valid job
+        costs. *)
+    Lemma concrete_valid_job_cost :
+      arrivals_have_valid_job_costs (concrete_arrival_sequence generate_jobs_at ts).
+    Proof.
+      move=> j [t /mem_bigcat_exists [tsk [TSK_IN IN]]].
+      move: (H_job_generation_valid_jobs tsk _ _ _ IN) => [JOB_TASK [_ JOB_COST]].
+      by rewrite /valid_job_cost JOB_TASK.
+    Qed.
+
+  End ValidityClaims.
+
+  (** In this section, we prove a series of facts regarding the maximal arrival
+      sequence, leading up to the main theorem that all arrival-curve
+      constraints are respected. *)
+  Section Facts.
+
+    (** Let [tsk] be any task in [ts] that is to be analyzed. *)
+    Variable tsk : Task.
+    Hypothesis H_tsk_in_ts : tsk \in ts.
+
+    (** First, we show that the arrivals at time [t] are indeed generated by
+        [generate_jobs_at] applied at time [t]. *)
+    Lemma task_arrivals_at_eq_generate_jobs_at:
+      forall t,
+        task_arrivals_at (concrete_arrival_sequence generate_jobs_at ts) tsk t
+        = generate_jobs_at tsk (max_arrivals_at tsk t) t.
+    Proof.
+      move=> t.
+      rewrite /task_arrivals_at bigcat_filter_eq_filter_bigcat bigcat_seq_uniqK // => tsk0 j INj.
+      apply H_job_generation_valid_jobs in INj.
+      by destruct INj.
+    Qed.
+
+    (** Next, we show that the number of arrivals at time [t] always matches
+        [max_arrivals_at] applied at time [t]. *)
+    Lemma task_arrivals_at_eq:
+      forall t,
+        size (task_arrivals_at (concrete_arrival_sequence generate_jobs_at ts) tsk t)
+        = max_arrivals_at tsk t.
+    Proof.
+      move=> t.
+      rewrite task_arrivals_at_eq_generate_jobs_at //.
+      by apply H_job_generation_valid_number.
+    Qed.
+
+    (** We then generalize the previous result to an arbitrary interval
+        <<[t1,t2)>>. *)
+    Lemma number_of_task_arrivals_eq :
+      forall t1 t2,
+        number_of_task_arrivals (concrete_arrival_sequence generate_jobs_at ts) tsk t1 t2
+        = \sum_(t1 <= t < t2) max_arrivals_at tsk t.
+    Proof.
+      move=> t1 t2.
+      rewrite /number_of_task_arrivals task_arrivals_between_is_cat_of_task_arrivals_at -size_big_nat.
+      apply eq_big_nat => t RANGE.
+      by apply task_arrivals_at_eq.
+    Qed.
+
+    (** We further show that, starting from an empty prefix and applying
+        [extend_arrival_prefix] [t] times, we end up with a prefix of size
+        [t]...  *)
+    Lemma extend_horizon_size :
+      forall t,
+        size (iter t (extend_arrival_prefix tsk) [::]) = t.
+    Proof. by elim=> // t IHt; rewrite size_cat IHt //=; lia. Qed.
+
+    (** ...and that the arrival sequence prefix up to an arbitrary horizon
+        [t] is a sequence of [t+1] elements. *)
+    Lemma prefix_up_to_size :
+      forall t,
+        size (maximal_arrival_prefix tsk t) = t.+1.
+    Proof.
+      by elim=> // t IHt; rewrite /maximal_arrival_prefix /extend_arrival_prefix  size_cat IHt //=; lia.
+    Qed.
+
+    (** Next, we prove prefix inclusion for [maximal_arrival_prefix] when the
+        horizon is expanded by one...  *)
+    Lemma n_arrivals_at_prefix_inclusion1 :
+      forall t h,
+        t <= h ->
+        nth 0 (maximal_arrival_prefix tsk h) t
+        = nth 0 (maximal_arrival_prefix tsk h.+1) t.
+    Proof.
+      move=> t h LEQ.
+      rewrite /maximal_arrival_prefix //= {3}/extend_arrival_prefix nth_cat prefix_up_to_size.
+      by case: (ltnP t h.+1); lia.
+    Qed.
+
+    (** ...and we generalize the previous result to two arbitrary horizons [h1 <= h2]. *)
+    Lemma n_arrivals_at_prefix_inclusion :
+      forall t h1 h2,
+        t <= h1 <= h2 ->
+        nth 0 (maximal_arrival_prefix tsk h1) t = nth 0 (maximal_arrival_prefix tsk h2) t.
+    Proof.
+      move=> t h1 h2 /andP[LEQh1 LEQh2].
+      induction h2; [by have -> : h1 = 0; lia |].
+      rewrite leq_eqVlt in LEQh2.
+      move: LEQh2 => /orP [/eqP EQ | LT]; first by rewrite EQ.
+      feed IHh2; first by lia.
+      rewrite -n_arrivals_at_prefix_inclusion1 //.
+      by lia.
+    Qed.
+
+    (** Next, we prove that, for any positive time instant [t], [max_arrivals_at] indeed
+        matches the arrivals of [next_max_arrival] applied at [t-1]. *)
+    Lemma max_arrivals_at_next_max_arrivals_eq:
+      forall t,
+        0 < t ->
+        max_arrivals_at tsk t
+        = next_max_arrival tsk (maximal_arrival_prefix tsk t.-1).
+    Proof.
+      move => t GT0.
+      move: prefix_up_to_size; rewrite /maximal_arrival_prefix => PUS.
+      rewrite /max_arrivals_at /maximal_arrival_prefix {1}/extend_arrival_prefix nth_cat extend_horizon_size //= ltnn //= subnn //=.
+      by destruct t.
+    Qed.
+
+    (** Given a time instant [t] and and interval [Δ], we show that
+        [max_arrivals_at] applied at time [t] is always less-or-equal to
+        [max_arrivals] applied to [Δ+1], even when each value of
+        [max_arrivals_at] in the interval <<[t-Δ, t)>> is subtracted from it. *)
+    Lemma n_arrivals_at_leq :
+      forall t Δ,
+        Δ <= t ->
+        max_arrivals_at tsk t
+        <= max_arrivals tsk Δ.+1 - \sum_(t - Δ <= i < t) max_arrivals_at tsk i.
+    Proof.
+      move=> t Δ LEQ.
+      move: (H_valid_arrival_curve tsk H_tsk_in_ts) => [ZERO MONO].
+      destruct t.
+      { rewrite unlock //= subn0.
+        rewrite /max_arrivals_at /maximal_arrival_prefix /extend_arrival_prefix
+                /next_max_arrival //= /suffix_sum subn0 unlock subn0.
+        by apply MONO. }
+      { rewrite max_arrivals_at_next_max_arrivals_eq; last by done.
+        rewrite /next_max_arrival /jobs_remaining prefix_up_to_size.
+        simpl (t.+1.-1).
+        destruct supremum eqn:SUP; last by  move:(supremum_none _ _ SUP); rewrite map_cons.
+        eapply (supremum_spec _ leqnn leq_total leq_trans _ _ SUP).
+        rewrite /suffix_sum prefix_up_to_size /max_arrivals_at.
+        have -> : \sum_(t.+1 - Δ <= i < t.+1) nth 0 (maximal_arrival_prefix tsk i) i =
+                 \sum_(t.+1 - Δ <= i < t.+1) nth 0 (maximal_arrival_prefix tsk t) i.
+        { apply eq_big_nat => i RANGE.
+          by apply n_arrivals_at_prefix_inclusion; lia. }
+        set f := fun x => max_arrivals _ x.+1 - \sum_(t.+1-x <= i < t.+1) nth 0 (maximal_arrival_prefix _ t) i.
+        have-> : max_arrivals tsk Δ.+1 - \sum_(t.+1 - Δ <= i < t.+1) nth 0 (maximal_arrival_prefix tsk t) i = f Δ by done.
+        apply map_f.
+        by rewrite mem_iota; lia. }
+    Qed.
+
+  End Facts.
+
+  (** Finally, we prove our main result, that is, the proposed maximal arrival
+      sequence instantiation indeed respects all arrival-curve constraints. *)
+  Theorem concrete_is_arrival_curve :
+    taskset_respects_max_arrivals (concrete_arrival_sequence generate_jobs_at ts) ts.
+  Proof.
+    move=> tsk IN t1 t LEQ.
+    set Δ := t - t1.
+    replace t1 with (t-Δ); last by lia.
+    have LEQd: Δ <= t by lia.
+    generalize Δ LEQd; clear LEQ Δ LEQd.
+    induction t; move => Δ LEQ.
+    { rewrite sub0n.
+      rewrite number_of_task_arrivals_eq //.
+      by vm_compute; rewrite unlock. }
+    { rewrite number_of_task_arrivals_eq //.
+      destruct Δ; first by rewrite /index_iota subnn; vm_compute; rewrite unlock.
+      rewrite subSS.
+      specialize (IHt Δ).
+      feed IHt; first by lia.
+      rewrite number_of_task_arrivals_eq // in IHt.
+      rewrite big_nat_recr //=; last by lia.
+      rewrite -leq_subRL; first apply n_arrivals_at_leq; try lia.
+      move: (H_valid_arrival_curve tsk IN) => [ZERO MONO].
+      apply (leq_trans IHt).
+      by apply MONO. }
+  Qed.
+
+End MaximalArrivalSequence.
+
-- 
GitLab