Skip to content
Snippets Groups Projects
BertognaResponseTimeFP.v 28.4 KiB
Newer Older
Felipe Cerqueira's avatar
Felipe Cerqueira committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
Require Import Vbase ScheduleDefs BertognaResponseTimeDefs divround helper
               ssreflect ssrbool eqtype ssrnat seq fintype bigop div path tuple.

Module ResponseTimeIterationFP.

  Import Schedule ResponseTimeAnalysis.
  
    Context {Job: eqType}.
    Variable job_cost: Job -> nat.
    Variable job_deadline: Job -> nat.
    Variable job_task: Job -> sporadic_task.

    Variable num_cpus: nat.
    Variable higher_eq_priority: fp_policy.
    Hypothesis H_valid_policy: valid_fp_policy higher_eq_priority.

    (* Consider a task set ts. *)
    Variable ts: sporadic_taskset.
    (*Load seq_nat_notation.*)
        
    (* Next we define the fixed-point iteration for computing
       Bertogna's response-time bound for any task in ts. *)
    
    (* First, given a function containing known response-time bounds
       for the higher-priority tasks, we compute the response-time bound
       of tsk using the following fixed-point iteration: 

       R_tsk <- f^step (R_tsk),
         where f is the response-time recurrence,
         step is the number of iterations,
         and f^0 = task_cost tsk. *)
    Definition per_task_rta (tsk: sporadic_task)
                      (R_prev: seq task_with_response_time) (step: nat) :=
      iter step
        (fun t => task_cost tsk +
                  div_floor
                    (total_interference_bound_fp
                                      tsk R_prev t higher_eq_priority)
                    num_cpus)
        (task_cost tsk).

    (* To ensure that the iteration converges, we will apply per_task_rta
       a "sufficient" number of times: task_deadline tsk + 1.
       Note that (deadline + 1) is pessimistic, but we don't care about
       the precise runtime complexity here. *)
    Definition max_steps (tsk: sporadic_task) := task_deadline tsk + 1.
    
    (* Next, we compute the response-time bounds of the task set.
       The function either returns a list of pairs (tsk, R_tsk) for the
       entire taskset or None, if the analysis failed for some task.
       Assume that the task set is sorted in increasing priority order. *)

    Definition R_list_helper :=
      fun hp_pairs tsk =>
               if hp_pairs is Some rt_bounds then
                 let R := per_task_rta tsk rt_bounds (max_steps tsk) in
                   if R <= task_deadline tsk then
                     Some (rcons rt_bounds (tsk, R))
                   else None
               else None.

    Definition R_list' (ts: sporadic_taskset) : option (seq task_with_response_time) :=
      foldl R_list_helper (Some [::]) ts.

    (*Compute (foldl (fun prev x => rcons prev x) [::] [:: 1; 2; 3; 4]).*)
    
    Definition R_list := R_list' ts.

    Definition fp_schedulability_test := R_list != None.
    
    Section AuxiliaryLemmas.

      Lemma R_list_rcons_prefix :
        forall ts hp_bounds tsk1 tsk2 R,
          R_list' (rcons ts tsk1) = Some (rcons hp_bounds (tsk2, R)) ->
            R_list' ts = Some hp_bounds.
      Proof.
        intros ts hp_bounds tsk1 tsk2 R SOME.
        rewrite -cats1 in SOME.
        unfold R_list' in *.
        rewrite foldl_cat in SOME.
        simpl in SOME.
        unfold R_list_helper in SOME.
        desf; rewrite Heq; rename H0 into EQ.
        move: EQ => /eqP EQ.
        rewrite eqseq_rcons in EQ.
        move: EQ => /andP [/eqP EQ _].
        by f_equal.
      Qed. 

      Lemma R_list_rcons_task :
        forall ts hp_bounds tsk1 tsk2 R,
          R_list' (rcons ts tsk1) = Some (rcons hp_bounds (tsk2, R)) ->
            tsk1 = tsk2.
      Proof.
        intros ts hp_bounds tsk1 tsk2 R SOME.
        rewrite -cats1 in SOME.
        unfold R_list' in *.
        rewrite foldl_cat in SOME.
        simpl in SOME.
        unfold R_list_helper in SOME.
        desf; rename H0 into EQ.
        move: EQ => /eqP EQ.
        rewrite eqseq_rcons in EQ.
        move: EQ => /andP [_ /eqP EQ].
        by inversion EQ.
      Qed. 

      Lemma R_list_rcons_response_time :
        forall ts hp_bounds tsk R,
          R_list' (rcons ts tsk) = Some (rcons hp_bounds (tsk, R)) ->
            R = per_task_rta tsk hp_bounds (max_steps tsk). 
      Proof.
        intros ts hp_bounds tsk R SOME.
        rewrite -cats1 in SOME.
        unfold R_list' in SOME.
        rewrite foldl_cat in SOME.
        simpl in SOME.
        unfold R_list_helper in SOME.
        desf; rename H0 into EQ; move: EQ => /eqP EQ.
        rewrite eqseq_rcons in EQ; move: EQ => /andP [/eqP EQ1 /eqP EQ2].
        by inversion EQ2; rewrite EQ1.
      Qed.

      Lemma R_list_contains_tasks :
        forall ts rt_bounds tsk R,
          R_list' ts = Some rt_bounds ->
          ((tsk, R) \in rt_bounds -> tsk \in ts).
      Proof.
        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
        {
          intros rt_bounds tsk R SOME.
          by inversion SOME; subst; rewrite 2!in_nil.
        }
        {
          intros rt_bounds tsk_i R SOME IN.
          destruct (lastP rt_bounds) as [| rt_bounds (tsk_lst', R_lst)];
            first by inversion SOME; desf.
          rewrite mem_rcons in_cons in IN.
          move: IN => /orP [/eqP HEAD | TAIL].
          {
            apply R_list_rcons_task in SOME; subst tsk_lst'.
            by inversion HEAD; rewrite mem_rcons in_cons; apply/orP; left.
          }
          {
            rewrite mem_rcons in_cons; apply/orP; right.
            apply R_list_rcons_prefix in SOME.
            by apply IHts with (rt_bounds := rt_bounds) (R := R); last by ins.
          }
        }
      Qed. 
      
      Lemma R_list_le_deadline :
        forall ts rt_bounds tsk R,
          R_list' ts = Some rt_bounds ->
          (tsk, R) \in rt_bounds ->
          R <= task_deadline tsk.
      Proof.
        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
        {
          intros rt_bounds tsk R SOME IN.
          by inversion SOME; subst; rewrite in_nil in IN.
        }
        {
          intros rt_bounds tsk_i R SOME IN.
          destruct (lastP rt_bounds) as [|rt_bounds (tsk_lst', R_lst)];
            first by rewrite in_nil in IN.
          rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
          destruct IN as [LAST | FRONT].
          {
            move: LAST => /eqP LAST.
            rewrite -cats1 in SOME.
            unfold R_list' in *.
            rewrite foldl_cat in SOME.
            simpl in SOME.
            unfold R_list_helper in SOME.
            desf; rename H0 into EQ.
            move: EQ => /eqP EQ.
            rewrite eqseq_rcons in EQ.
            move: EQ => /andP [_ /eqP EQ].
            inversion EQ; subst.
            by apply Heq0.
          }
          {
            apply IHts with (rt_bounds := rt_bounds); last by ins.
            by apply R_list_rcons_prefix in SOME.
          }
        }
      Qed.

      Lemma R_list_ge_cost :
        forall ts rt_bounds tsk R,
          R_list' ts = Some rt_bounds ->
          (tsk, R) \in rt_bounds ->
          R >= task_cost tsk.
      Proof.
        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
        {
          intros rt_bounds tsk R SOME IN.
          by inversion SOME; subst; rewrite in_nil in IN.
        }
        {
          intros rt_bounds tsk_i R SOME IN.
          destruct (lastP rt_bounds) as [|rt_bounds (tsk_lst', R_lst)];
            first by rewrite in_nil in IN.
          rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
          destruct IN as [LAST | FRONT].
          {
            move: LAST => /eqP LAST.
            rewrite -cats1 in SOME.
            unfold R_list' in *.
            rewrite foldl_cat in SOME.
            simpl in SOME.
            unfold R_list_helper in SOME.
            desf; rename H0 into EQ.
            move: EQ => /eqP EQ.
            rewrite eqseq_rcons in EQ.
            move: EQ => /andP [_ /eqP EQ].
            inversion EQ; subst.
            by destruct (max_steps tsk_lst');
              [by apply leqnn | by apply leq_addr].
          }
          {
            apply IHts with (rt_bounds := rt_bounds); last by ins.
            by apply R_list_rcons_prefix in SOME.
          }
        }
      Qed.

        
      Lemma R_list_non_empty :
        forall ts rt_bounds tsk,
          R_list' ts = Some rt_bounds ->
          (tsk \in ts <->
            exists R,
              (tsk, R) \in rt_bounds).
      Proof.
        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
        {
          intros rt_bounds tsk SOME.
          inversion SOME; rewrite in_nil; split; first by ins.
          by intro EX; des; rewrite in_nil in EX.
        }
        {
          intros rt_bounds tsk_i SOME.
          destruct (lastP rt_bounds) as [|rt_bounds (tsk_lst', R_lst)].
          {
            split; last first; intro EX; des; first by rewrite in_nil in EX.
            unfold R_list' in *.
            rewrite -cats1 foldl_cat in SOME.
            simpl in SOME.
            unfold R_list_helper in *; desf; rename H0 into EQ.
            destruct l; first by ins.
            by rewrite rcons_cons in EQ; inversion EQ.
          }
          split.
          {
            intros IN; rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
            destruct IN as [LAST | FRONT].
            {
              move: LAST => /eqP LAST; subst tsk_i.
              generalize SOME; apply R_list_rcons_task in SOME; subst tsk_lst'; intro SOME.
              exists R_lst.
              by rewrite mem_rcons in_cons; apply/orP; left.
            }
            {
              apply R_list_rcons_prefix in SOME.
              exploit (IHts rt_bounds tsk_i); [by ins | intro EX].
              apply EX in FRONT; des.
              by exists R; rewrite mem_rcons in_cons; apply/orP; right.
            }
          }
          {
            intro IN; des.
            rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
            destruct IN as [LAST | FRONT].
            {
              move: LAST => /eqP LAST.
              inversion LAST; subst tsk_i R; clear LAST.
              apply R_list_rcons_task in SOME; subst.
              by rewrite mem_rcons in_cons; apply/orP; left.
            }
            {
              rewrite mem_rcons in_cons; apply/orP; right.
              exploit (IHts rt_bounds tsk_i);
                [by apply R_list_rcons_prefix in SOME | intro EX].
              by apply EX; exists R.
            }
          }
        }
      Qed.

      Lemma per_task_rta_fold :
        forall tsk rt_bounds,
          task_cost tsk +
           div_floor (total_interference_bound_fp tsk rt_bounds
                     (per_task_rta tsk rt_bounds (max_steps tsk)) higher_eq_priority) num_cpus
          = per_task_rta tsk rt_bounds (max_steps tsk).+1.
      Proof.
          by ins.
      Qed.
      
    End AuxiliaryLemmas.
    
    Section Proof.

      (* Assume that higher_eq_priority is a total order over the task set. *)
      Hypothesis H_reflexive: reflexive higher_eq_priority.
      Hypothesis H_transitive: transitive higher_eq_priority.
      Hypothesis H_unique_priorities: antisymmetric higher_eq_priority.
      Hypothesis H_total: total higher_eq_priority.

      (* Assume the task set has no duplicates, ... *)
      Hypothesis H_ts_is_a_set: uniq ts.

      (* ...all tasks have valid parameters, ... *)
      Hypothesis H_valid_task_parameters: valid_sporadic_taskset ts.

      (* ...restricted deadlines, ...*)
      Hypothesis H_restricted_deadlines:
        forall tsk, tsk \in ts -> task_deadline tsk <= task_period tsk.

      (* ...and tasks are ordered by increasing priorities. *)
      Hypothesis H_sorted_ts: sorted higher_eq_priority ts.

      (* Next, consider any arrival sequence such that...*)
      Context {arr_seq: arrival_sequence Job}.

     (* ...all jobs come from task set ts, ...*)
      Hypothesis H_all_jobs_from_taskset:
        forall (j: JobIn arr_seq), job_task j \in ts.
      
      (* ...they have valid parameters,...*)
      Hypothesis H_valid_job_parameters:
        forall (j: JobIn arr_seq),
          valid_sporadic_job job_cost job_deadline job_task j.
      
      (* ... and satisfy the sporadic task model.*)
      Hypothesis H_sporadic_tasks: sporadic_task_model arr_seq job_task.
      
      (* Then, consider any platform with at least one CPU and unit
         unit execution rate, where...*)
      Variable rate: Job -> processor num_cpus -> nat.
      Variable sched: schedule num_cpus arr_seq.
      Hypothesis H_at_least_one_cpu :
        num_cpus > 0.
      Hypothesis H_rate_equals_one :
        forall j cpu, rate j cpu = 1.

      (* ...jobs only execute after they arrived and no longer
         than their execution costs,... *)
      Hypothesis H_jobs_must_arrive_to_execute:
        jobs_must_arrive_to_execute sched.
      Hypothesis H_completed_jobs_dont_execute:
        completed_jobs_dont_execute job_cost rate sched.

      (* ...and do not execute in parallel. *)
      Hypothesis H_no_parallelism:
        jobs_dont_execute_in_parallel sched.

      (* Assume the platform satisfies the global scheduling invariant. *)
      Hypothesis H_global_scheduling_invariant:
        forall (tsk: sporadic_task) (j: JobIn arr_seq) (t: time),
          tsk \in ts ->
          job_task j = tsk ->
          backlogged job_cost rate sched j t ->
          count
            (fun tsk_other : _ =>
               is_interfering_task_fp tsk higher_eq_priority tsk_other &&
               task_is_scheduled job_task sched tsk_other t) ts = num_cpus.

      Definition no_deadline_missed_by (tsk: sporadic_task) :=
        task_misses_no_deadline job_cost job_deadline job_task
                                rate sched tsk.

      (* Now we present the proofs of termination and correctness of
         the schedulability test. *)

      Lemma R_list_unzip1 :
        forall ts tsk hp_bounds R,
          uniq ts ->
          sorted higher_eq_priority (rcons ts tsk) ->
          R_list' (rcons ts tsk) = Some (rcons hp_bounds (tsk, R)) ->
            [seq tsk_hp <- ts | is_interfering_task_fp tsk higher_eq_priority tsk_hp] =
            unzip1 hp_bounds.
      Proof.
        clear H_sorted_ts H_global_scheduling_invariant H_no_parallelism H_completed_jobs_dont_execute
              H_jobs_must_arrive_to_execute H_jobs_must_arrive_to_execute
              H_rate_equals_one H_at_least_one_cpu sched rate H_sporadic_tasks H_all_jobs_from_taskset.
        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
        {
          admit.
        }
        {
          intros tsk hp_bounds R UNIQ SORTED SOME; simpl.
destruct (lastP hp_bounds) as [| hp_bounds (tsk_lst', R_lst)].
          {
            admit.
          }

          rewrite filter_rcons.
          assert (HP: is_interfering_task_fp tsk higher_eq_priority tsk_lst).
          {
            admit.
          } rewrite HP.

          
          assert (SHIFT: [seq tsk_hp <- ts' | is_interfering_task_fp tsk higher_eq_priority tsk_hp] = [seq tsk_hp <- ts' | is_interfering_task_fp tsk_lst higher_eq_priority tsk_hp]).
          {
            apply eq_filter. red.
            admit.
          } rewrite SHIFT.

          unfold unzip1; rewrite map_rcons.
          simpl; f_equal; last by admit.
          apply R_list_rcons_prefix in SOME.
          generalize SOME; apply R_list_rcons_task in SOME; subst tsk_lst'; intro SOME.
          
          apply IHts with (R := R_lst); simpl in *; last by ins.
            by rewrite rcons_uniq in UNIQ; move: UNIQ => /andP [_ UNIQ].
            by apply sorted_rcons_prefix in SORTED.
        }
      Qed.
      
      (*  To prove convergence of R, we first show convergence of rt_rec. *)
      Lemma per_task_rta_converges:
        forall (tsk: sporadic_task) prev,
          tsk \in ts ->
          per_task_rta tsk prev (max_steps tsk) <= task_deadline tsk ->
          per_task_rta tsk prev (max_steps tsk) =
            per_task_rta tsk prev (max_steps tsk).+1.
      Proof.
        rename H_valid_task_parameters into TASKPARAMS.
        unfold valid_sporadic_taskset, valid_sporadic_task in *.

        (* To simplify, let's call the function f.*)
        intros tsk prev INtsk LE; set (f := per_task_rta tsk prev); fold f in LE.

        assert (INprev: forall i, i \in prev -> fst i \in ts).
        {
          unfold f in *.
          admit.
        }
        assert (GE_COST: forall i,i \in prev -> snd i >= task_cost (fst i)).
          admit.
        
        (* First prove that f is monotonic.*)
        assert (MON: forall x1 x2, x1 <= x2 -> f x1 <= f x2).
        {
          intros x1 x2 LEx; unfold f, per_task_rta.
          apply fun_mon_iter_mon; [by ins | by ins; apply leq_addr |].
          clear LEx x1 x2; intros x1 x2 LEx.
          
          unfold div_floor, total_interference_bound_fp.
          rewrite big_seq_cond [\sum_(i <- _ | let '(tsk_other, _) := i in
                                   _ && (tsk_other != tsk))_]big_seq_cond.
          rewrite leq_add2l leq_div2r // leq_sum //.
          intros i; specialize (INprev i); specialize (GE_COST i).
          destruct i as [i R]; move => /andP [IN _].
          unfold interference_bound; simpl.
          rewrite leq_min; apply/andP; split.
          {
            apply leq_trans with (n := W i R x1); 
              first by apply geq_minl.            
            exploit (TASKPARAMS i); [by apply INprev | intro PARAMS; des].
            by apply W_monotonic; try (by ins); apply GE_COST.
          }
          {
            apply leq_trans with (n := x1 - task_cost tsk + 1);
              first by apply geq_minr.
            by rewrite leq_add2r leq_sub2r //.
          }
        }

        (* Either f converges by the deadline or not. *)
        unfold max_steps in *; rewrite -> addn1 in *.
        destruct ([exists k in 'I_(task_deadline tsk).+1,
                     f k == f k.+1]) eqn:EX.
        {
          move: EX => /exists_inP EX; destruct EX as [k _ ITERk].
          move: ITERk => /eqP ITERk.
          by apply iter_fix with (k := k);
            [by ins | by apply ltnW, ltn_ord].
        }
        apply negbT in EX; rewrite negb_exists_in in EX.
        move: EX => /forall_inP EX.
        assert (GROWS: forall k: 'I_(task_deadline tsk).+1,
                         f k < f k.+1).
        {
          intros k; rewrite ltn_neqAle; apply/andP; split; first by apply EX.
          apply MON, leqnSn.
        }

        (* If it doesn't converge, then it becomes larger than the deadline.
           But initialy we assumed otherwise. Contradiction! *)
        assert (BY1: f (task_deadline tsk).+1 > task_deadline tsk).
        {
          clear MON LE EX.
          induction (task_deadline tsk).+1; first by ins.
          apply leq_ltn_trans with (n := f n);
            last by apply (GROWS (Ordinal (ltnSn n))).
          apply IHn; intros k.
          by apply (GROWS (widen_ord (leqnSn n) k)).
        }
        by apply leq_ltn_trans with (m := f (task_deadline tsk).+1) in BY1;
          [by rewrite ltnn in BY1 | by ins].
      Qed.
      
      Lemma R_list_has_response_time_bounds :
        forall rt_bounds tsk R,
          R_list = Some rt_bounds ->
          (tsk, R) \in rt_bounds ->
          forall j : JobIn arr_seq,
            job_task j = tsk ->
            completed job_cost rate sched j (job_arrival j + R).
      Proof.
        rename H_valid_job_parameters into JOBPARAMS,
               H_valid_task_parameters into TASKPARAMS,
               H_restricted_deadlines into RESTR,
               H_completed_jobs_dont_execute into COMP,
               H_jobs_must_arrive_to_execute into MUSTARRIVE,
               H_global_scheduling_invariant into INVARIANT,
               H_sorted_ts into SORT,
               H_transitive into TRANS,
               H_unique_priorities into UNIQ,
               H_total into TOTAL,
               H_all_jobs_from_taskset into ALLJOBS,
               H_ts_is_a_set into SET.
        clear ALLJOBS.
        have CONV := per_task_rta_converges.
        
        (*intros rt_bounds tsk R SOME IN.
        exploit (R_list_non_empty ts rt_bounds tsk);
          [by apply SOME| intro EX].
        destruct EX as [_ EX].
        exploit EX; [by exists R | intro IN'].
        exploit (R_list_unzip1 tsk rt_bounds); [by ins | by ins | intro UNZIP].
        clear IN' EX.
        generalize dependent R.
        generalize dependent tsk.
        generalize dependent rt_bounds.*)
        
        unfold fp_schedulability_test, R_list in *.
        induction ts as [| ts' tsk_i] using last_ind.
        {
          intros rt_bounds tsk R SOME IN.
          by inversion SOME; subst; rewrite in_nil in IN.
        }
        {
          intros rt_bounds tsk R SOME IN j JOBj.
          destruct (lastP rt_bounds) as [| hp_bounds (tsk_lst, R_lst)];
            first by rewrite in_nil in IN.
          rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
          destruct IN as [LAST | BEGINNING]; last first.
          {
            apply IHs with (rt_bounds := hp_bounds) (tsk := tsk); try (by ins).
            by rewrite rcons_uniq in SET; move: SET => /andP [_ SET].
            by ins; red; ins; apply TASKPARAMS; rewrite mem_rcons in_cons; apply/orP; right.
            by ins; apply RESTR; rewrite mem_rcons in_cons; apply/orP; right.
            by apply sorted_rcons_prefix in SORT.
            {
              intros tsk0 j0 t IN0 JOB0 BACK0.
              exploit (INVARIANT tsk0 j0 t); try (by ins);
                [by rewrite mem_rcons in_cons; apply/orP; right | intro INV].
              rewrite -cats1 count_cat /= in INV.
              unfold is_interfering_task_fp in INV.
              generalize SOME; apply R_list_rcons_task in SOME; subst tsk_i; intro SOME.
              assert (HP: higher_eq_priority tsk_lst tsk0 = false).
              {
                apply order_sorted_rcons with (x := tsk0) in SORT; [|by ins | by ins].
                apply negbTE; apply/negP; unfold not; intro BUG.
                exploit UNIQ; [by apply/andP; split; [by apply SORT | by ins] | intro EQ].
                by rewrite rcons_uniq -EQ IN0 in SET.
              }              
              by rewrite HP 2!andFb 2!addn0 in INV.
            }
            by ins; apply CONV; [by rewrite mem_rcons in_cons; apply/orP; right | by ins].
            by apply R_list_rcons_prefix in SOME.
            (*{
              unfold unzip1 in UNZIP.
              rewrite map_rcons in UNZIP.
              rewrite filter_rcons in UNZIP.
              assert (HP: is_interfering_task_fp tsk higher_eq_priority tsk_i = false).
              {
                apply negbTE; unfold is_interfering_task_fp.
                apply/negP; unfold not; move => /andP [HP NEQ].
                apply R_list_rcons_prefix in SOME.
                have EX := R_list_non_empty ts' hp_bounds tsk SOME.
                destruct EX as [_ EX].
                exploit EX; [by exists R | intro IN].
                apply order_sorted_rcons with (x := tsk) in SORT; try (by ins).
                unfold is_interfering_task_fp.
                exploit (UNIQ tsk_i tsk);
                  [by apply/andP; split | intro EQ].
                by rewrite EQ eq_refl in NEQ.
              }
              rewrite HP in UNZIP.
              move: UNZIP => /eqP UNZIP.
              rewrite eqseq_rcons in UNZIP.
              move: UNZIP => /andP [/eqP UNZIP _].
              by apply UNZIP.
            }*)
          }
          {
            move: LAST => /eqP LAST.
            inversion LAST as [[EQ1 EQ2]].
            rewrite -> EQ1 in *; rewrite -> EQ2 in *; clear EQ1 EQ2 LAST.
            generalize SOME; apply R_list_rcons_task in SOME; subst tsk_i; intro SOME.
            generalize SOME; apply R_list_rcons_prefix in SOME; intro SOME'.
            have BOUND := bertogna_cirinei_response_time_bound_fp.
            unfold is_response_time_bound_of_task, job_has_completed_by in BOUND.
            apply BOUND with (job_deadline := job_deadline) (job_task := job_task) (tsk := tsk_lst)
                             (ts := rcons ts' tsk_lst) (hp_bounds := hp_bounds)
                             (higher_eq_priority := higher_eq_priority); clear BOUND; try (by ins).
            (*{
              unfold unzip1 in UNZIP.
              rewrite filter_rcons map_rcons in UNZIP.
              unfold is_interfering_task_fp at 1 in UNZIP.
              rewrite eq_refl andbF in UNZIP.
              rewrite filter_rcons.
              unfold is_interfering_task_fp at 1.
              rewrite eq_refl andbF. fold 
              admit.
            }*)
            {
              intros hp_tsk R0 HP j0 JOB0.
              apply IHs with (rt_bounds := hp_bounds) (tsk := hp_tsk); try (by ins).
              by rewrite rcons_uniq in SET; move: SET => /andP [_ SET].
              by red; ins; apply TASKPARAMS; rewrite mem_rcons in_cons; apply/orP; right.
              by ins; apply RESTR; rewrite mem_rcons in_cons; apply/orP; right.
              by apply sorted_rcons_prefix in SORT.
              {
                intros tsk0 j1 t IN0 JOB1 BACK0.
                exploit (INVARIANT tsk0 j1 t); try (by ins);
                  [by rewrite mem_rcons in_cons; apply/orP; right | intro INV].
                rewrite -cats1 count_cat /= addn0 in INV.
                unfold is_interfering_task_fp in INV.
                assert (NOINTERF: higher_eq_priority tsk_lst tsk0 = false).
                {
                  apply order_sorted_rcons with (x := tsk0) in SORT; [|by ins | by ins].
                  apply negbTE; apply/negP; unfold not; intro BUG.
                  exploit UNIQ; [by apply/andP; split; [by apply BUG | by ins] | intro EQ].
                  by rewrite rcons_uniq EQ IN0 in SET.
                }
                by rewrite NOINTERF 2!andFb addn0 in INV.
              }
              by ins; apply CONV; [by rewrite mem_rcons in_cons; apply/orP; right | by ins].  
            }
            by ins; apply R_list_ge_cost with (ts := ts') (rt_bounds := hp_bounds).
            by ins; apply R_list_le_deadline with (ts := ts') (rt_bounds := hp_bounds).
            {
              ins; exploit (INVARIANT tsk_lst j0 t); try (by ins).
              by rewrite mem_rcons in_cons; apply/orP; left.
            }
            {
              rewrite [R_lst](R_list_rcons_response_time ts' hp_bounds tsk_lst); last by ins.
              rewrite per_task_rta_fold; apply CONV;
                first by rewrite mem_rcons in_cons; apply/orP; left.
              apply R_list_le_deadline with (ts := rcons ts' tsk_lst)
                                            (rt_bounds := rcons hp_bounds (tsk_lst, R_lst));
                first by apply SOME'.
              rewrite mem_rcons in_cons; apply/orP; left; apply/eqP; f_equal; symmetry.
              by apply R_list_rcons_response_time with (ts := ts'). 
            }
          }
        }
      Qed.

      (* Finally, we show that if the schedulability test suceeds, ...*)
      Hypothesis H_test_passes: fp_schedulability_test.
      
      (*..., then no task misses its deadline. *)
      Theorem taskset_schedulable_by_fp_rta :
        forall tsk, tsk \in ts -> no_deadline_missed_by tsk.
      Proof.
        unfold no_deadline_missed_by, task_misses_no_deadline,
               job_misses_no_deadline, completed,
               fp_schedulability_test,
               valid_sporadic_job in *.
        rename H_valid_job_parameters into JOBPARAMS,
               H_valid_task_parameters into TASKPARAMS,
               H_restricted_deadlines into RESTR,
               H_completed_jobs_dont_execute into COMP,
               H_jobs_must_arrive_to_execute into MUSTARRIVE,
               H_global_scheduling_invariant into INVARIANT,
               H_sorted_ts into SORT,
               H_transitive into TRANS,
               H_unique_priorities into UNIQ,
               H_total into TOTAL,
               H_all_jobs_from_taskset into ALLJOBS,
               H_test_passes into TEST.

        move => tsk INtsk j /eqP JOBtsk.
        have RLIST := (R_list_has_response_time_bounds).
        have NONEMPTY := (R_list_non_empty ts).
        have DL := (R_list_le_deadline ts).

        unfold R_list in *; destruct (R_list' ts) as [rt_bounds |]; last by ins.
        exploit (NONEMPTY rt_bounds tsk); [by ins | by ins | intro EX; des].
        exploit (RLIST rt_bounds tsk R); [by ins | by ins | by apply JOBtsk | intro COMPLETED ].
        exploit (DL rt_bounds tsk R); [by ins | by ins | clear DL; intro DL].

        rewrite eqn_leq; apply/andP; split; first by apply service_interval_le_cost.
        apply leq_trans with (n := service rate sched j (job_arrival j + R)); last first.
        {
          unfold valid_sporadic_taskset, valid_sporadic_task in *.
          apply service_monotonic; rewrite leq_add2l.
          specialize (JOBPARAMS j); des; rewrite JOBPARAMS1.
          by rewrite JOBtsk.
        }
        rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
        by apply COMPLETED.
      Qed.

    End Proof.

  End ResponseTimeIterationFP.