From 3e0a4feef44845e7637f4f274b86de53f22bf7c9 Mon Sep 17 00:00:00 2001 From: Eric Hulburd Date: Mon, 25 Jan 2021 19:02:09 -0800 Subject: [PATCH 1/2] refactor chip-contiguous-subschedule-from-last-instructions to non-recursive --- src/addresser/outgoing-schedule.lisp | 56 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/addresser/outgoing-schedule.lisp b/src/addresser/outgoing-schedule.lisp index 0209f4eb2..47f2579f3 100644 --- a/src/addresser/outgoing-schedule.lisp +++ b/src/addresser/outgoing-schedule.lisp @@ -123,39 +123,37 @@ If POINT is generated by CHIP-SCHEDULE-RESOURCE-CARVING-POINT, then the resultin #'< :key (lambda (i) (gethash i (chip-schedule-times schedule))))) -;; TODO Make this non-recursive so we can avoid blowing the stack on -;; veeeerrrrry deep programs. -(defun chip-contiguous-subschedule-from-last-instructions (schedule resource) - "Returns an unordered contiguous subsequence of instructions from SCHEDULE where each instruction is in the dependency graph of the last instructions in SCHEDULE and touches only resources in RESOURCE." +(defun mark-predecessors-seen (instr earlier-instrs seen) + "performs a depth first search on INSTR as the root node and marks all of its descendants as true in hash-table SEEN." + (let ((queue (list instr))) + (loop :while queue :do + (let* ((v (pop queue)) + (predecessors (gethash v earlier-instrs))) + (loop :for predecessor :in predecessors :do + (unless (gethash predecessor seen) + (setf (gethash predecessor seen) t) + (push predecessor queue))))))) + +(defun chip-contiguous-subschedule-from-last-instructions (schedule resource) + "loops over the last instructions in the SCHEDULE and returns an arbitrarily ordered list of instructions in the SCHEDULE that are contiguous and involve a subset of resources in RESOURCE." (let* ((lsched (chip-schedule-data schedule)) - (last-instrs (lscheduler-last-instrs lsched)) (earlier-instrs (lscheduler-earlier-instrs lsched)) (seen (make-hash-table)) + (leaves (lscheduler-last-instrs lsched)) (sched nil)) - (labels ((mark-predecessors-seen (instr) - (cond ((resource= (instruction-resources instr) - resource) - (setf (gethash instr seen) t)) - ((resource-subsetp (instruction-resources instr) - resource) - (map nil #'mark-predecessors-seen (gethash instr earlier-instrs))))) - (bottoms-up (instr) - ;; Recursively explorer earlier instructions in the - ;; schedule. Instructions are collected if their - ;; resources are a subset of RESOURCE. If a carving - ;; point is encountered, mark all earlier instructions - ;; as seen. - (unless (gethash instr seen) - (setf (gethash instr seen) t) - (cond - ((carving-point-p resource instr) - (map nil #'mark-predecessors-seen (reverse (gethash instr earlier-instrs)))) - ((and (resources-intersect-p resource (instruction-resources instr)) - (not (carving-point-p resource instr))) - (push instr sched) - (map nil #'bottoms-up (reverse (gethash instr earlier-instrs)))))))) - (map nil #'bottoms-up last-instrs) - sched))) + (loop :while leaves :do + (let ((instr (pop leaves))) + (unless (gethash instr seen) + (setf (gethash instr seen) t) + (cond + ((and (resources-intersect-p resource (instruction-resources instr)) + (resource-subsetp (instruction-resources instr) resource)) + (push instr sched) + (loop :for earlier-instr :in (gethash instr earlier-instrs) :do + (push earlier-instr leaves))) + ((carving-point-p resource instr) + (mark-predecessors-seen instr earlier-instrs seen)))))) + sched)) (defun chip-schedule-qubit-times (schedule) "Find the first time a qubit is available, for each qubit in the schedule." From 9d1be803e1d8c0a4b267c0323531687838cbdb74 Mon Sep 17 00:00:00 2001 From: Eric Hulburd Date: Wed, 27 Jan 2021 11:36:27 -0800 Subject: [PATCH 2/2] add contiguous subschedule spec for callstack exhaustion --- src/addresser/outgoing-schedule.lisp | 32 +++++++--------------------- tests/addresser-tests.lisp | 23 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/addresser/outgoing-schedule.lisp b/src/addresser/outgoing-schedule.lisp index 47f2579f3..f289674cc 100644 --- a/src/addresser/outgoing-schedule.lisp +++ b/src/addresser/outgoing-schedule.lisp @@ -108,34 +108,18 @@ BEFORE-INST to make use of RESOURCE." :when (carving-point-p resource instr) :maximize (chip-schedule-end-time schedule instr))) -(defun chip-schedule-from-carving-point (schedule resource point) - "Returns the (time-ordered) subsequence of instructions from SCHEDULE which intersect RESOURCE and which start on or after the time POINT. - -If POINT is generated by CHIP-SCHEDULE-RESOURCE-CARVING-POINT, then the resulting subsequence has a further \"information light-cone\" property: SCHEDULE will have no other instructions which can receive information from RESOURCE from after POINT." - ;; NOTE: This could be written in such a way that GETHASH is called only once: - ;; grab it inside of LOOP and attach it to INSTR by a CONS cell, then - ;; change SORT's KEY to grab that value, then strip the cells away at end. - (sort - (loop :for instr :being :the :hash-keys :of (chip-schedule-times schedule) - :when (and (<= point (chip-schedule-start-time schedule instr)) - (resources-intersect-p resource (instruction-resources instr))) - :collect instr) - #'< - :key (lambda (i) (gethash i (chip-schedule-times schedule))))) - (defun mark-predecessors-seen (instr earlier-instrs seen) - "performs a depth first search on INSTR as the root node and marks all of its descendants as true in hash-table SEEN." - (let ((queue (list instr))) - (loop :while queue :do - (let* ((v (pop queue)) - (predecessors (gethash v earlier-instrs))) - (loop :for predecessor :in predecessors :do + "Performs a depth first search on INSTR as the root node and marks all of its descendants as true in hash-table SEEN." + (let ((stack (list instr))) + (loop :while stack :do + (let ((predecessors (gethash (pop stack) earlier-instrs))) + (dolist (predecessor predecessors) (unless (gethash predecessor seen) (setf (gethash predecessor seen) t) - (push predecessor queue))))))) + (push predecessor stack))))))) (defun chip-contiguous-subschedule-from-last-instructions (schedule resource) - "loops over the last instructions in the SCHEDULE and returns an arbitrarily ordered list of instructions in the SCHEDULE that are contiguous and involve a subset of resources in RESOURCE." + "Returns an unordered list of instructions from SCHEDULE such that each instruction involves a subset of RESOURCE. Traversal of the schedule begins from the latest scheduled instructions and works backwards into earlier instructions until an instruction uses resources not in RESOURCE." (let* ((lsched (chip-schedule-data schedule)) (earlier-instrs (lscheduler-earlier-instrs lsched)) (seen (make-hash-table)) @@ -149,7 +133,7 @@ If POINT is generated by CHIP-SCHEDULE-RESOURCE-CARVING-POINT, then the resultin ((and (resources-intersect-p resource (instruction-resources instr)) (resource-subsetp (instruction-resources instr) resource)) (push instr sched) - (loop :for earlier-instr :in (gethash instr earlier-instrs) :do + (dolist (earlier-instr (gethash instr earlier-instrs)) (push earlier-instr leaves))) ((carving-point-p resource instr) (mark-predecessors-seen instr earlier-instrs seen)))))) diff --git a/tests/addresser-tests.lisp b/tests/addresser-tests.lisp index 34b83f5c7..40615070a 100644 --- a/tests/addresser-tests.lisp +++ b/tests/addresser-tests.lisp @@ -100,3 +100,26 @@ (quil::chip-contiguous-subschedule-from-last-instructions sched (quil::make-qubit-resource 0 2)) expected-subschedule)))))) + +(deftest test-fidelity-addresser-subschedule-on-deep-circuit () + (let* ((chip (quil::build-nq-fully-connected-chip 3)) + (sched (quil::make-chip-schedule chip)) + (h0 (build-gate "H" nil 0)) + (circuit-depth 25000)) + (loop :for i :from 1 :to circuit-depth :do + (progn + ;; these gates will exercise depth in the outer dfs, ie in + ;; chip-contiguous-subschedule-from-last-instructions. + (quil::chip-schedule-append sched (build-gate "H" nil 0)) + ;; these gates will exercise depth in the inner dfs, ie in + ;; mark-predecessors-seen. + (quil::chip-schedule-append sched (build-gate "H" nil 1)))) + (flet ((is-h0 (gate) + (and (string= (quil::application-operator-root-name gate) + (quil::application-operator-root-name h0)) + (equalp (quil::application-parameters gate) + (quil::application-parameters h0))))) + (let ((result (quil::chip-contiguous-subschedule-from-last-instructions sched (quil::make-qubit-resource 0)))) + (is (= (length result) circuit-depth)) + (is (every #'is-h0 result)))))) +