Rules¶
Give the rules of an experiment in a Python file, with qdevices send ... --rules FILE. A rule decides
whether a run goes on. The generic rules of the app always run too.
qdevices send examples/euroqexa-three-jobs/manifest.json --live --max-order 1 --rules examples/rules_bell.py
qdevices send examples/euroqexa-three-jobs/manifest.json --live --resume RECORD --max-order 3 --rules examples/rules_bell.py
Warning
A rules file runs with your rights and can read the rest of the environment. The token variable is already deleted when the file is imported. Give only a file you have read.
The functions¶
Function |
Called |
With |
|---|---|---|
|
once a call, before its first job |
the read of the machine |
|
before each job is sent |
the job, the state of the run |
|
after each result line is on disk |
the job, the result, the state |
|
after a refusal, a failed job, or a job never submitted |
the job, what happened |
Each gets plain dicts (no site object, no token) and answers with a verdict:
{"rule": "bell", "passed": True}
{"rule": "bell", "passed": False, "reason": "00 and 11 in 0.31 of the shots"}
{"rule": "pick", "passed": True, "skip": [4, 5]}
A verdict that does not pass stops the run, with exit code 2. Its reason is in the record.
skipnames orders not yet sent: they are never sent in that record. An order that was sent, or that does not exist, stops the run.A failed verdict: a function that raises, an answer that is not a verdict, a key that is not a text, or the key
self.Any other key is kept in the
ruleline, but not a key the line already has (event,utc,app,site,machine,project,point,order, and on VLQlexis_projectandresource). Anoteis also printed, as aNOTEline after the line of the rule.At
before_call,before_jobandafter_result, every generic rule and your rule must pass. Youron_refusalreplaces the generic one, so an experiment can let a refusal go on.
Argument |
What it holds |
|---|---|
|
the job of the manifest ( |
|
the result line, with |
|
|
|
|
Bit order. A rule that reads a bit by its position must do so per site. On Piast-Q, qubit 0 is the
leftmost character of each key of counts: element i of a shot is qubit i (release 1.15.0 of the maker’s
client library), and the app joins the shot in that order. On Euro-Q-Exa and VLQ the keys are as the
site gives them; LRZ publishes no bit order. On Euro-Q-Exa, as measured with this app and not published by
LRZ, a key reads q[n-1] … q[0], so q[0] is the rightmost character: a job with H on q[2] varied only the
leftmost. Qrisp’s label of a variable reads q[0] first, so reverse a key to compare it with get_measurement
(Circuits written in Qrisp).
The generic rules¶
Point |
Rule |
Passes when |
|---|---|---|
|
|
Euro-Q-Exa: the site gives the machine as online; Piast-Q: its name is in the broker’s list (Piast-Q (PCSS)); VLQ: the token is a member of the LEXIS project |
|
|
VLQ: no flag of the status file is |
|
|
the shots are within the limit of the site and |
|
|
Euro-Q-Exa: the shots times the gate operations of the text ( |
|
|
the seconds used so far plus |
|
|
VLQ only: the token has 30 minutes or more left, or twice |
|
|
Piast-Q only, when a window is set: the time is inside it |
|
|
the result has counts by bit string, and all the shots asked came back |
|
|
the job has a measured time, from 0 to |
|
|
never: a refusal, a failed job or a job never submitted stops the run |
The example file¶
examples/rules_bell.py stops the run if a Bell job gives the two even outcomes in less than half its
shots:
"""An example rules file: stop the run if a Bell job gives the two even outcomes in less than half its shots.
A rule gets plain dicts and answers with a verdict. A verdict that does not pass stops the run. Use it with:
qdevices send examples/euroqexa-three-jobs/manifest.json --live --max-order 3 --rules examples/rules_bell.py
"""
def after_result(job: dict, result: dict, state: dict) -> dict:
"""The verdict on one result: a Bell job passes when 00 and 11 hold at least half of its shots."""
if not job["name"].startswith("BELL"):
return {"rule": "bell", "passed": True}
counts = result["counts"]
even = counts.get("00", 0) + counts.get("11", 0)
share = even / job["shots"]
return {"rule": "bell", "passed": share >= 0.5, "share": share,
"reason": f"00 and 11 in {share:.2f} of the shots, below 0.5"}
The rules file in the record¶
The record is held to the rules file of its first call. Its start line holds rules_file: the path and
SHA-256 of that file, or null with no --rules. The SHA-256 covers that file alone, not the modules it
imports. The app reads the file once and runs the bytes it hashes.
Call |
Rules file |
|---|---|
a resume that sends ( |
must be the one the record is held to, or it is refused before anything is sent: give that file with |
a resume with |
changes it on purpose: the resume line holds the new file in |
a resume that collects only |
never refused for its rules file |
the commands the app prints ( |
give |
qdevices send MANIFEST --live --resume RECORD --max-order N --rules FILE --new-rules
Each resume line holds rules_file, new_rules (true with --new-rules) and rules_note, the note the
app printed about the rules file, if any. A record of an older version of the app has no rules_file. It
is held to the rules file of its first resume that sends or gives --new-rules; that resume is not refused,
and its line holds a note and no rules_before. A resume that collects only before then sets nothing, and
its line and the commands it prints hold its rules file, with a note.