From 8ec504846e204349e3439ec760e02532897c9cb1 Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Mon, 4 Apr 2022 10:36:45 +0200 Subject: [PATCH 01/10] moved old configuration files with incompatible 'gate_decomposition' entries (containing " " instead of "," as separator) to subdir 'depr'. Also see https://github.com/QuTech-Delft/OpenQL/issues/444 --- .../measurement/openql_experiments/config_cc_s17_vsm.json.in | 0 .../measurement/openql_experiments/config_cc_s5_direct_iq.json.in | 0 .../pycqed}/measurement/openql_experiments/config_cc_s7.json.in | 0 .../measurement/openql_experiments/config_cc_s7_direct_iq.json.in | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {pycqed => deprecated/pycqed}/measurement/openql_experiments/config_cc_s17_vsm.json.in (100%) rename {pycqed => deprecated/pycqed}/measurement/openql_experiments/config_cc_s5_direct_iq.json.in (100%) rename {pycqed => deprecated/pycqed}/measurement/openql_experiments/config_cc_s7.json.in (100%) rename {pycqed => deprecated/pycqed}/measurement/openql_experiments/config_cc_s7_direct_iq.json.in (100%) diff --git a/pycqed/measurement/openql_experiments/config_cc_s17_vsm.json.in b/deprecated/pycqed/measurement/openql_experiments/config_cc_s17_vsm.json.in similarity index 100% rename from pycqed/measurement/openql_experiments/config_cc_s17_vsm.json.in rename to deprecated/pycqed/measurement/openql_experiments/config_cc_s17_vsm.json.in diff --git a/pycqed/measurement/openql_experiments/config_cc_s5_direct_iq.json.in b/deprecated/pycqed/measurement/openql_experiments/config_cc_s5_direct_iq.json.in similarity index 100% rename from pycqed/measurement/openql_experiments/config_cc_s5_direct_iq.json.in rename to deprecated/pycqed/measurement/openql_experiments/config_cc_s5_direct_iq.json.in diff --git a/pycqed/measurement/openql_experiments/config_cc_s7.json.in b/deprecated/pycqed/measurement/openql_experiments/config_cc_s7.json.in similarity index 100% rename from pycqed/measurement/openql_experiments/config_cc_s7.json.in rename to deprecated/pycqed/measurement/openql_experiments/config_cc_s7.json.in diff --git a/pycqed/measurement/openql_experiments/config_cc_s7_direct_iq.json.in b/deprecated/pycqed/measurement/openql_experiments/config_cc_s7_direct_iq.json.in similarity index 100% rename from pycqed/measurement/openql_experiments/config_cc_s7_direct_iq.json.in rename to deprecated/pycqed/measurement/openql_experiments/config_cc_s7_direct_iq.json.in From 9773b482459dad68f0941e0516386b7770d8c10b Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Mon, 4 Apr 2022 15:41:49 +0200 Subject: [PATCH 02/10] use CQASM 1.0 for QI test cases --- .../config/config_cc_s17_direct_iq.json.in | 2 +- pycqed/tests/openql/test_cqasm.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in b/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in index 740f9c8df1..2bb7fb4a5d 100644 --- a/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in +++ b/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in @@ -500,7 +500,7 @@ }, // Parameterized gate decompositions (test) - "_test_rotate": { + "_rx": { "prototype": ["X:qubit", "L:int"], "duration": @MW_DURATION@, "decomposition": { diff --git a/pycqed/tests/openql/test_cqasm.py b/pycqed/tests/openql/test_cqasm.py index ff0aeea5cc..843cd1b264 100644 --- a/pycqed/tests/openql/test_cqasm.py +++ b/pycqed/tests/openql/test_cqasm.py @@ -171,7 +171,8 @@ def test_qi_barrier(self): # File: {name}.cq # Purpose: test qi barrier - version 1.2 + version 1.0 + qubits 5 pragma @ql.name("{name}") # set the name of generated files @@ -190,7 +191,8 @@ def test_qi_curly_brackets(self): # File: {name}.cq # Purpose: test qi curly brackets - version 1.2 + version 1.0 + qubits 5 pragma @ql.name("{name}") # set the name of generated files @@ -207,7 +209,8 @@ def test_qi_wait(self): # File: {name}.cq # Purpose: test qi wait - version 1.2 + version 1.0 + qubits 5 pragma @ql.name("{name}") # set the name of generated files From 3c34c40878c3e3c9bae7b5f48e16602c7dcc7c71 Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Fri, 20 May 2022 16:13:12 +0200 Subject: [PATCH 03/10] dded tests and configuration for random gates --- .../config/common_instructions.json.in | 158 +++++++++++++++++- .../config/config_cc_s17_direct_iq.json.in | 49 ------ .../openql_experiments/cqasm/special_cq.py | 1 + .../openql_experiments/openql_helpers.py | 21 +++ pycqed/tests/openql/test_cqasm.py | 80 ++++++++- 5 files changed, 253 insertions(+), 56 deletions(-) diff --git a/pycqed/measurement/openql_experiments/config/common_instructions.json.in b/pycqed/measurement/openql_experiments/config/common_instructions.json.in index 32e1ca53fb..fe5abdb08e 100644 --- a/pycqed/measurement/openql_experiments/config/common_instructions.json.in +++ b/pycqed/measurement/openql_experiments/config/common_instructions.json.in @@ -637,6 +637,20 @@ // measure //************************************************************************************************************** + "measure": { + "prototype": ["M:qubit"], + "duration": @RO_DURATION@, + "cc": { + "signal": [ + { "type": "measure", + "operand_idx": 0, + "value": ["dummy"] // Future extension: specify output and weight, and generate code word + } + ], + "static_codeword_override": [0] // FIXME + } + }, + // allow decompositions that prepend measurement with microwave gate "_do_measure": { "prototype": ["M:qubit"], @@ -651,7 +665,8 @@ "static_codeword_override": [0] // FIXME } }, - "measure": { + // FIXME: fails if used in conjunction with legacy API + "_measure": { "prototype": ["M:qubit"], "duration": 0, "decomposition": { @@ -670,6 +685,147 @@ } }, + + //************************************************************************************************************** + // Parameterized gate decompositions + // Require OpenQL >= 0.10.5 with passes 'opt.ConstProp' and 'opt.DeadCodeElim' enabled + //************************************************************************************************************** + + // Parameterized gate decompositions (test) + "_rx": { + "prototype": ["X:qubit", "L:int"], + "duration": 0, + "decomposition": { + "into": [ // FIXME: makes no real sense, should match gateset used by QI + "if (op(1) < 45) {", + " rx45 op(0)", + "} else {", + " rx90 op(0)", + "}" + ] + } + }, + // Randomized banchmarking (test) + // Based on epstein_efficient_decomposition + "_test_epstein": { + "prototype": ["X:qubit", "R:int"], + "duration": 0, + "decomposition": { + // NB: to meet timing, the CC backend of OpenQL would need to implement a computed goto for this long if-tree + // Alternatively, a binary tree could help improve timing + "into": [ + "if (op(1) == 0) {", + " i op(0)", + "} else if (op(1) == 1) {", + " y90 op(0)", + " x90 op(0)", + "} else if (op(1) == 2) {", + " mx90 op(0)", + " my90 op(0)", + "} else if (op(1) == 3) {", + " x180 op(0)", + "} else if (op(1) == 4) {", + " my90 op(0)", + " mx90 op(0)", + "} else if (op(1) == 5) {", + " x90 op(0)", + " my90 op(0)", + "} else if (op(1) == 6) {", + " y180 op(0)", + "} else if (op(1) == 7) {", + " my90 op(0)", + " x90 op(0)", + "} else if (op(1) == 8) {", + " x90 op(0)", + " y90 op(0)", + "} else if (op(1) == 9) {", + " x180 op(0)", + " y180 op(0)", + "} else if (op(1) == 10) {", + " y90 op(0)", + " mx90 op(0)", + "} else if (op(1) == 11) {", + " mx90 op(0)", + " y90 op(0)", + "} else if (op(1) == 12) {", + " y90 op(0)", + " x180 op(0)", + "} else if (op(1) == 13) {", + " mx90 op(0)", + "} else if (op(1) == 14) {", + " x90 op(0)", + " my90 op(0)", + " mx90 op(0)", + "} else if (op(1) == 15) {", + " my90 op(0)", + "} else if (op(1) == 16) {", + " x90 op(0)", + "} else if (op(1) == 17) {", + " x90 op(0)", + " y90 op(0)", + " x90 op(0)", + "} else if (op(1) == 18) {", + " my90 op(0)", + " x180 op(0)", + "} else if (op(1) == 19) {", + " x90 op(0)", + " y180 op(0)", + "} else if (op(1) == 20) {", + " x90 op(0)", + " my90 op(0)", + " x90 op(0)", + "} else if (op(1) == 21) {", + " y90 op(0)", + "} else if (op(1) == 22) {", + " mx90 op(0)", + " y180 op(0)", + "} else if (op(1) == 23) {", + " x90 op(0)", + " y90 op(0)", + " mx90 op(0)", + "}" + // FIXME: else Error + ] + } + }, + + // based on TwoQubitClifford::gate_decomposition + "_test_decompose_2q_clifford": { + "prototype": ["X:qubit", "X:qubit", "L:int"], + "duration": 0, + "decomposition": { + "into": [ + "if (op(2) < 576) {", +// " _test_single_qubit_like_gates op(0),op(1),op(2)", + " rx90 op(0)", + "} else if (op(2) < 576 + 5184) {", +// " _test_CNOT_like_gates op(0),op(1),op(2)", + " rx90 op(0)", + "}" // FIXME: etc + ] + } + }, + "_test_single_qubit_like_gates": { + "prototype": ["X:qubit", "X:qubit", "R:int", "R:int"], + "duration": 0, + "decomposition": { + // FIXME: becomes sequential if op(0) and op(1) are handled by same sequencer (and also if not!) + "into": [ + " _test_epstein op(0), op(2)", + " _test_epstein op(1), op(3)" + ] + } + }, + "_test_CNOT_like_gates": { + "prototype": ["X:qubit", "X:qubit", "R:int", "R:int", "R:int", "R:int"], + "duration": 0, + "decomposition": { + "into": [ + " rx90 op(0)" + ] + } + }, + //************************************************************************************************************** // flux //************************************************************************************************************** diff --git a/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in b/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in index 2bb7fb4a5d..e51dc509a1 100644 --- a/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in +++ b/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in @@ -499,55 +499,6 @@ } }, - // Parameterized gate decompositions (test) - "_rx": { - "prototype": ["X:qubit", "L:int"], - "duration": @MW_DURATION@, - "decomposition": { - "into": [ // FIXME: makes no real sense, and currently fails in backend - "if (op(1) < 45) {", - " rx45 op(0)", - "} else {", - " rx90 op(0)", - "}" - ] - } - }, - - // Randomized banchmarking (test) - // based on TwoQubitClifford::gate_decomposition - "_test_decompose_2q_clifford": { - "prototype": ["X:qubit", "X:qubit", "L:int"], - "duration": @MW_DURATION@, // FIXME: depends - "decomposition": { - "into": [ // FIXME: currently fails in backend - "if (op(2) < 576) {", -// " _test_single_qubit_like_gates op(0),op(1),op(2)", - " rx90 op(0)", - "} else if (op(2) < 576 + 5184) {", -// " _test_CNOT_like_gates op(0),op(1),op(2)", - " rx90 op(0)", - "}" // FIXME: etc - ] - } - }, - "_test_single_qubit_like_gates": { - "prototype": ["X:qubit", "X:qubit", "L:int"], - "duration": @MW_DURATION@, // FIXME: depends - "decomposition": { - "into": [ // FIXME: currently fails in backend - ] - } - }, - "_test_CNOT_like_gates": { - "prototype": ["X:qubit", "X:qubit", "L:int"], - "duration": @MW_DURATION@, // FIXME: depends - "decomposition": { - "into": [ // FIXME: currently fails in backend - ] - } - }, - // Refocussing (test) // CZ with park and refocus "__cz_sw_ne_park_refocus": { diff --git a/pycqed/measurement/openql_experiments/cqasm/special_cq.py b/pycqed/measurement/openql_experiments/cqasm/special_cq.py index 42ae4de92a..85f52a2895 100644 --- a/pycqed/measurement/openql_experiments/cqasm/special_cq.py +++ b/pycqed/measurement/openql_experiments/cqasm/special_cq.py @@ -168,6 +168,7 @@ def active_reset( map qubit = q[{qubit_idx}] .init + # FIXME: """ p = OqlProgram(name, platf_cfg) # NB: name must be identical to name set by "pragma @ql.name" above diff --git a/pycqed/measurement/openql_experiments/openql_helpers.py b/pycqed/measurement/openql_experiments/openql_helpers.py index f7f11acc67..45b2e6cf0e 100644 --- a/pycqed/measurement/openql_experiments/openql_helpers.py +++ b/pycqed/measurement/openql_experiments/openql_helpers.py @@ -694,6 +694,27 @@ def _configure_compiler( } ) + if ql.get_version() >= '0.10.5': + # add constant propagation pass + c.append_pass( + 'opt.ConstProp', + 'const_prop', + { + 'output_prefix': 'test_output/%N.%P', + 'debug': 'yes' + } + ) + + # add dead code elimination pass + c.append_pass( + 'opt.DeadCodeElim', + 'dead_code_elim', + { + 'output_prefix': 'test_output/%N.%P', + 'debug': 'yes' + } + ) + # schedule c.append_pass( 'sch.ListSchedule', diff --git a/pycqed/tests/openql/test_cqasm.py b/pycqed/tests/openql/test_cqasm.py index 843cd1b264..14053712cf 100644 --- a/pycqed/tests/openql/test_cqasm.py +++ b/pycqed/tests/openql/test_cqasm.py @@ -9,6 +9,8 @@ #from utils import file_compare +import openql as ql + import pycqed.measurement.openql_experiments.generate_CC_cfg_modular as gen import pycqed.measurement.openql_experiments.cqasm.special_cq as spcq import pycqed.measurement.openql_experiments.openql_helpers as oqh @@ -80,7 +82,7 @@ def test_hierarchical_gate_decomposition(self): p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above p.compile_cqasm(src) - @unittest.skip("FIXME: disabled") + @unittest.skipIf(ql.get_version() < '0.10.5', "test requires later OpenQL verrsion") def test_experimental_functions(self): name = f'test_experimental_functions' src = f""" @@ -93,13 +95,79 @@ def test_experimental_functions(self): pragma @ql.name("{name}") # set the name of generated files map i = creg(0) + map foo = creg(60) map b = breg(0) # FIXME: assign on PL state, not DSM - # NB: on all CCIO: - set i = rnd_seed(0, 12345678) - set i = rnd_threshold(0, 0.5) - # set b = rnd(0) - cond (rnd(0)) rx180 q[0] + # Configure Random Number Generators. NB: on all CCIO: + set foo = rnd_seed(0, 12345678) + set foo = rnd_threshold(0, 0.5) + # set b = rnd_bit(0) + + cond (rnd_bit(0)) rx180 q[0] + """ + + p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above + p.compile_cqasm(src) + + @unittest.skipIf(ql.get_version() < '0.10.5', "test requires later OpenQL verrsion") + def test_rb_2q(self): + name = f'test_rb_2q' + qa = 'q[0]' + qb = 'q[1]' + src = f""" + # Note: file generated by {__file__}::test_rb_2q + # File: {name}.cq + # Purpose: test experimental functions + + version 1.2 + + pragma @ql.name("{name}") # set the name of generated files + + map i = creg(0) + map r = creg(1) + map r1 = creg(2) + map r2 = creg(3) + map r3 = creg(4) + map r4 = creg(5) + map foo = creg(31) + + # Configure Random Number Generators. NB: on all CCIO: + # Quoting PycQED: + # The two qubit clifford group (C2) consists of 11520 two-qubit cliffords + # These gates can be subdivided into four classes. + # 1. The Single-qubit like class | 576 elements (24^2) + # 2. The CNOT-like class | 5184 elements (24^2 * 3^2) + # 3. The iSWAP-like class | 5184 elements (24^2 * 3^2) + # 4. The SWAP-like class | 576 elements (24^2) + # --------------------------------|------------- + + # Two-qubit Clifford group C2 | 11520 elements + + .config_RND + set foo = rnd_seed(0, 12345678) + #set foo = rnd_range(0, 20) + set foo = rnd_seed(1, 12345678) + #set foo = rnd_range(1, 24) + set foo = rnd_seed(2, 12345678) + #set foo = rnd_range(2, 9) + + .rb_2q + for (i=0; i<10000; i=i+1) {{ + set r = rnd(0) + if(r < 1) {{ # single-qubit-like, probability 576/11520 = 1/20 + set r1 = rnd(1) + set r2 = rnd(1) + _test_single_qubit_like_gates {qa}, {qb}, r1, r2 + }} else if(r < 1+9) {{ # CNOT-like, probability 5184/11520 = 9/20 + set r1 = rnd(1) + set r2 = rnd(1) + set r3 = rnd(2) + set r4 = rnd(2) + _test_cnot_like_gates {qa}, {qb}, r1, r2, r3, r4 +# _test_CNOT_like_gates {qa}, {qb}, 1, 2, 3, 4 + }} else if(r < 1+9+9) {{ # iSWAP-like, probability 5184/11520 = 9/20 + }} else {{ # SWAP-like, probability 576/11520 = 1/20 + }} + }} """ p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above From 4f2e2a47b1b49d9276a14a335421684307ffe997 Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Mon, 23 May 2022 14:19:57 +0200 Subject: [PATCH 04/10] cleanup --- .../config/common_instructions.json.in | 75 +++++++++---------- pycqed/tests/openql/test_cqasm.py | 10 +-- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/pycqed/measurement/openql_experiments/config/common_instructions.json.in b/pycqed/measurement/openql_experiments/config/common_instructions.json.in index fe5abdb08e..8c796efd7f 100644 --- a/pycqed/measurement/openql_experiments/config/common_instructions.json.in +++ b/pycqed/measurement/openql_experiments/config/common_instructions.json.in @@ -693,27 +693,27 @@ // Parameterized gate decompositions (test) "_rx": { - "prototype": ["X:qubit", "L:int"], - "duration": 0, - "decomposition": { - "into": [ // FIXME: makes no real sense, should match gateset used by QI + "prototype": ["X:qubit", "L:int"], + "duration": 0, + "decomposition": { + "into": [ // FIXME: makes no real sense, should match gateset used by QI "if (op(1) < 45) {", - " rx45 op(0)", + " rx45 op(0)", "} else {", - " rx90 op(0)", + " rx90 op(0)", "}" ] - } + } }, // Randomized banchmarking (test) // Based on epstein_efficient_decomposition "_test_epstein": { - "prototype": ["X:qubit", "R:int"], - "duration": 0, - "decomposition": { + "prototype": ["X:qubit", "R:int"], + "duration": 0, + "decomposition": { // NB: to meet timing, the CC backend of OpenQL would need to implement a computed goto for this long if-tree // Alternatively, a binary tree could help improve timing - "into": [ + "into": [ "if (op(1) == 0) {", " i op(0)", "} else if (op(1) == 1) {", @@ -786,44 +786,37 @@ "}" // FIXME: else Error ] - } + } }, - // based on TwoQubitClifford::gate_decomposition - "_test_decompose_2q_clifford": { - "prototype": ["X:qubit", "X:qubit", "L:int"], - "duration": 0, - "decomposition": { - "into": [ - "if (op(2) < 576) {", -// " _test_single_qubit_like_gates op(0),op(1),op(2)", - " rx90 op(0)", - "} else if (op(2) < 576 + 5184) {", -// " _test_CNOT_like_gates op(0),op(1),op(2)", - " rx90 op(0)", - "}" // FIXME: etc - ] - } - }, "_test_single_qubit_like_gates": { - "prototype": ["X:qubit", "X:qubit", "R:int", "R:int"], - "duration": 0, - "decomposition": { + "prototype": ["X:qubit", "X:qubit", "R:int", "R:int"], + "duration": 0, + "decomposition": { // FIXME: becomes sequential if op(0) and op(1) are handled by same sequencer (and also if not!) - "into": [ - " _test_epstein op(0), op(2)", - " _test_epstein op(1), op(3)" + "into": [ + " _test_epstein op(0), op(2)", + " _test_epstein op(1), op(3)" ] - } + } }, "_test_CNOT_like_gates": { - "prototype": ["X:qubit", "X:qubit", "R:int", "R:int", "R:int", "R:int"], - "duration": 0, - "decomposition": { - "into": [ - " rx90 op(0)" + "prototype": ["X:qubit", "X:qubit", "R:int", "R:int", "R:int", "R:int"], + "duration": 0, + "decomposition": { + // op(0): + // op(1): + // op(2): rnd range [0,24) + // op(3): rnd range [0,24) + // op(4): rnd range [0,3) + // op(5): rnd range [0,3) + "into": [ + " _test_epstein op(0), op(2)", + " _test_epstein op(1), op(3)", + " cz op(0),op(1)" + // FIXME: S ] - } + } }, //************************************************************************************************************** diff --git a/pycqed/tests/openql/test_cqasm.py b/pycqed/tests/openql/test_cqasm.py index 14053712cf..b976cbfaa2 100644 --- a/pycqed/tests/openql/test_cqasm.py +++ b/pycqed/tests/openql/test_cqasm.py @@ -131,7 +131,7 @@ def test_rb_2q(self): map r4 = creg(5) map foo = creg(31) - # Configure Random Number Generators. NB: on all CCIO: + # Configure Random Number Generators. NB: on all modules: # Quoting PycQED: # The two qubit clifford group (C2) consists of 11520 two-qubit cliffords # These gates can be subdivided into four classes. @@ -143,12 +143,13 @@ def test_rb_2q(self): # Two-qubit Clifford group C2 | 11520 elements .config_RND + # NB: we are currently required by cQASM to assign the function result to a variable set foo = rnd_seed(0, 12345678) - #set foo = rnd_range(0, 20) + set foo = rnd_range(0, 20) set foo = rnd_seed(1, 12345678) - #set foo = rnd_range(1, 24) + set foo = rnd_range(1, 24) set foo = rnd_seed(2, 12345678) - #set foo = rnd_range(2, 9) + set foo = rnd_range(2, 3) .rb_2q for (i=0; i<10000; i=i+1) {{ @@ -163,7 +164,6 @@ def test_rb_2q(self): set r3 = rnd(2) set r4 = rnd(2) _test_cnot_like_gates {qa}, {qb}, r1, r2, r3, r4 -# _test_CNOT_like_gates {qa}, {qb}, 1, 2, 3, 4 }} else if(r < 1+9+9) {{ # iSWAP-like, probability 5184/11520 = 9/20 }} else {{ # SWAP-like, probability 576/11520 = 1/20 }} From 04e78d98e0754744afd924e55a43d70b5a5bac7e Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Fri, 24 Jun 2022 10:05:18 +0200 Subject: [PATCH 05/10] cleanup of gate decompositions (experimental section) --- .../config/common_instructions.json.in | 300 ++++++++++-------- pycqed/tests/openql/test_cqasm.py | 11 +- 2 files changed, 172 insertions(+), 139 deletions(-) diff --git a/pycqed/measurement/openql_experiments/config/common_instructions.json.in b/pycqed/measurement/openql_experiments/config/common_instructions.json.in index 8c796efd7f..28fdd6b966 100644 --- a/pycqed/measurement/openql_experiments/config/common_instructions.json.in +++ b/pycqed/measurement/openql_experiments/config/common_instructions.json.in @@ -685,140 +685,6 @@ } }, - - //************************************************************************************************************** - // Parameterized gate decompositions - // Require OpenQL >= 0.10.5 with passes 'opt.ConstProp' and 'opt.DeadCodeElim' enabled - //************************************************************************************************************** - - // Parameterized gate decompositions (test) - "_rx": { - "prototype": ["X:qubit", "L:int"], - "duration": 0, - "decomposition": { - "into": [ // FIXME: makes no real sense, should match gateset used by QI - "if (op(1) < 45) {", - " rx45 op(0)", - "} else {", - " rx90 op(0)", - "}" - ] - } - }, - // Randomized banchmarking (test) - // Based on epstein_efficient_decomposition - "_test_epstein": { - "prototype": ["X:qubit", "R:int"], - "duration": 0, - "decomposition": { - // NB: to meet timing, the CC backend of OpenQL would need to implement a computed goto for this long if-tree - // Alternatively, a binary tree could help improve timing - "into": [ - "if (op(1) == 0) {", - " i op(0)", - "} else if (op(1) == 1) {", - " y90 op(0)", - " x90 op(0)", - "} else if (op(1) == 2) {", - " mx90 op(0)", - " my90 op(0)", - "} else if (op(1) == 3) {", - " x180 op(0)", - "} else if (op(1) == 4) {", - " my90 op(0)", - " mx90 op(0)", - "} else if (op(1) == 5) {", - " x90 op(0)", - " my90 op(0)", - "} else if (op(1) == 6) {", - " y180 op(0)", - "} else if (op(1) == 7) {", - " my90 op(0)", - " x90 op(0)", - "} else if (op(1) == 8) {", - " x90 op(0)", - " y90 op(0)", - "} else if (op(1) == 9) {", - " x180 op(0)", - " y180 op(0)", - "} else if (op(1) == 10) {", - " y90 op(0)", - " mx90 op(0)", - "} else if (op(1) == 11) {", - " mx90 op(0)", - " y90 op(0)", - "} else if (op(1) == 12) {", - " y90 op(0)", - " x180 op(0)", - "} else if (op(1) == 13) {", - " mx90 op(0)", - "} else if (op(1) == 14) {", - " x90 op(0)", - " my90 op(0)", - " mx90 op(0)", - "} else if (op(1) == 15) {", - " my90 op(0)", - "} else if (op(1) == 16) {", - " x90 op(0)", - "} else if (op(1) == 17) {", - " x90 op(0)", - " y90 op(0)", - " x90 op(0)", - "} else if (op(1) == 18) {", - " my90 op(0)", - " x180 op(0)", - "} else if (op(1) == 19) {", - " x90 op(0)", - " y180 op(0)", - "} else if (op(1) == 20) {", - " x90 op(0)", - " my90 op(0)", - " x90 op(0)", - "} else if (op(1) == 21) {", - " y90 op(0)", - "} else if (op(1) == 22) {", - " mx90 op(0)", - " y180 op(0)", - "} else if (op(1) == 23) {", - " x90 op(0)", - " y90 op(0)", - " mx90 op(0)", - "}" - // FIXME: else Error - ] - } - }, - - "_test_single_qubit_like_gates": { - "prototype": ["X:qubit", "X:qubit", "R:int", "R:int"], - "duration": 0, - "decomposition": { - // FIXME: becomes sequential if op(0) and op(1) are handled by same sequencer (and also if not!) - "into": [ - " _test_epstein op(0), op(2)", - " _test_epstein op(1), op(3)" - ] - } - }, - "_test_CNOT_like_gates": { - "prototype": ["X:qubit", "X:qubit", "R:int", "R:int", "R:int", "R:int"], - "duration": 0, - "decomposition": { - // op(0): - // op(1): - // op(2): rnd range [0,24) - // op(3): rnd range [0,24) - // op(4): rnd range [0,3) - // op(5): rnd range [0,3) - "into": [ - " _test_epstein op(0), op(2)", - " _test_epstein op(1), op(3)", - " cz op(0),op(1)" - // FIXME: S - ] - } - }, - //************************************************************************************************************** // flux //************************************************************************************************************** @@ -1043,6 +909,172 @@ "break": 0 } } + }, + + //************************************************************************************************************** + // Experimental section for new features: names start with "__" to prevent clashes + // Require OpenQL >= 0.10.5 with passes 'opt.ConstProp' and 'opt.DeadCodeElim' enabled + //************************************************************************************************************** + + // Parameterized gate decompositions (test) + "__rx": { + "prototype": ["X:qubit", "L:int"], + "duration": 0, + "decomposition": { + "into": [ // FIXME: makes no real sense, should match gateset used by QI + "if (op(1) < 45) {", + " rx45 op(0)", + "} else {", + " rx90 op(0)", + "}" + ] + } + }, + // Randomized banchmarking (test) + // Based on epstein_efficient_decomposition + "__test_epstein": { + "prototype": ["X:qubit", "R:int"], + "duration": 0, + "decomposition": { + // NB: to meet timing, the CC backend of OpenQL would need to implement a computed goto for this long if-tree + // Alternatively, a binary tree could help improve timing + "into": [ + "if (op(1) == 0) {", + " i op(0)", + "} else if (op(1) == 1) {", + " y90 op(0)", + " x90 op(0)", + "} else if (op(1) == 2) {", + " mx90 op(0)", + " my90 op(0)", + "} else if (op(1) == 3) {", + " x180 op(0)", + "} else if (op(1) == 4) {", + " my90 op(0)", + " mx90 op(0)", + "} else if (op(1) == 5) {", + " x90 op(0)", + " my90 op(0)", + "} else if (op(1) == 6) {", + " y180 op(0)", + "} else if (op(1) == 7) {", + " my90 op(0)", + " x90 op(0)", + "} else if (op(1) == 8) {", + " x90 op(0)", + " y90 op(0)", + "} else if (op(1) == 9) {", + " x180 op(0)", + " y180 op(0)", + "} else if (op(1) == 10) {", + " y90 op(0)", + " mx90 op(0)", + "} else if (op(1) == 11) {", + " mx90 op(0)", + " y90 op(0)", + "} else if (op(1) == 12) {", + " y90 op(0)", + " x180 op(0)", + "} else if (op(1) == 13) {", + " mx90 op(0)", + "} else if (op(1) == 14) {", + " x90 op(0)", + " my90 op(0)", + " mx90 op(0)", + "} else if (op(1) == 15) {", + " my90 op(0)", + "} else if (op(1) == 16) {", + " x90 op(0)", + "} else if (op(1) == 17) {", + " x90 op(0)", + " y90 op(0)", + " x90 op(0)", + "} else if (op(1) == 18) {", + " my90 op(0)", + " x180 op(0)", + "} else if (op(1) == 19) {", + " x90 op(0)", + " y180 op(0)", + "} else if (op(1) == 20) {", + " x90 op(0)", + " my90 op(0)", + " x90 op(0)", + "} else if (op(1) == 21) {", + " y90 op(0)", + "} else if (op(1) == 22) {", + " mx90 op(0)", + " y180 op(0)", + "} else if (op(1) == 23) {", + " x90 op(0)", + " y90 op(0)", + " mx90 op(0)", + "}" + // FIXME: else Error + ] + } + }, + + "__test_single_qubit_like_gates": { + "prototype": ["X:qubit", "X:qubit", "R:int", "R:int"], + "duration": 0, + "decomposition": { + // FIXME: becomes sequential if op(0) and op(1) are handled by same sequencer (and also if not!) + "into": [ + " __test_epstein op(0), op(2)", + " __test_epstein op(1), op(3)" + ] + } + }, + "__test_CNOT_like_gates": { + "prototype": ["X:qubit", "X:qubit", "R:int", "R:int", "R:int", "R:int"], + "duration": 0, + "decomposition": { + // op(0): + // op(1): + // op(2): rnd range [0,24) + // op(3): rnd range [0,24) + // op(4): rnd range [0,3) + // op(5): rnd range [0,3) + "into": [ + " __test_epstein op(0), op(2)", + " __test_epstein op(1), op(3)", + " cz op(0),op(1)" + // FIXME: S + ] + } + }, + + //************************************************************************************************************** + // Experimental decomposition to Waveforms + //************************************************************************************************************** + + "__cz_sw_ne_park": { + "prototype": ["Z:qubit", "Z:qubit", "I:qubit"], + "duration": 0, //@FLUX_DURATION@, + "decomposition": { + "into": [ + "__play op(0), \"flux\", {|\"type\": \"cz\", \"which\": \"SW\", \"cw\": 3|}", + "__play op(1), \"flux\", {|\"type\": \"idle_z\", \"which\": \"NE\", \"cw\": 1|}", + "__play op(2), \"flux\", {|\"type\": \"park\", \"cw\": 5|}" + ] + } + }, + + + // FIXME: add duration + // FIXME: add decomposition key + + // Native waveform gates: + "__play": { + "duration": @FLUX_DURATION@, // FIXME + "prototype": [ + "Z:qubit", // qubit used as part of port + "L:string", // port part 2 + "L:json" // waveform + ] } + + + // }, // end of "instructions" diff --git a/pycqed/tests/openql/test_cqasm.py b/pycqed/tests/openql/test_cqasm.py index b976cbfaa2..7f85877e12 100644 --- a/pycqed/tests/openql/test_cqasm.py +++ b/pycqed/tests/openql/test_cqasm.py @@ -82,7 +82,7 @@ def test_hierarchical_gate_decomposition(self): p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above p.compile_cqasm(src) - @unittest.skipIf(ql.get_version() < '0.10.5', "test requires later OpenQL verrsion") + @unittest.skipIf(ql.get_version() < '0.10.5', "test requires later OpenQL version") def test_experimental_functions(self): name = f'test_experimental_functions' src = f""" @@ -95,7 +95,7 @@ def test_experimental_functions(self): pragma @ql.name("{name}") # set the name of generated files map i = creg(0) - map foo = creg(60) + map foo = creg(31) map b = breg(0) # FIXME: assign on PL state, not DSM # Configure Random Number Generators. NB: on all CCIO: @@ -109,7 +109,8 @@ def test_experimental_functions(self): p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above p.compile_cqasm(src) - @unittest.skipIf(ql.get_version() < '0.10.5', "test requires later OpenQL verrsion") + @unittest.skipIf(ql.get_version() < '0.10.5', "test requires later OpenQL version") + # FIXME: fails with "Inconsistency detected in bundle contents: time travel not yet possible in this version" def test_rb_2q(self): name = f'test_rb_2q' qa = 'q[0]' @@ -157,13 +158,13 @@ def test_rb_2q(self): if(r < 1) {{ # single-qubit-like, probability 576/11520 = 1/20 set r1 = rnd(1) set r2 = rnd(1) - _test_single_qubit_like_gates {qa}, {qb}, r1, r2 + __test_single_qubit_like_gates {qa}, {qb}, r1, r2 }} else if(r < 1+9) {{ # CNOT-like, probability 5184/11520 = 9/20 set r1 = rnd(1) set r2 = rnd(1) set r3 = rnd(2) set r4 = rnd(2) - _test_cnot_like_gates {qa}, {qb}, r1, r2, r3, r4 + __test_cnot_like_gates {qa}, {qb}, r1, r2, r3, r4 }} else if(r < 1+9+9) {{ # iSWAP-like, probability 5184/11520 = 9/20 }} else {{ # SWAP-like, probability 576/11520 = 1/20 }} From 5a719d094b48559c4937652563f1f921451c8dd9 Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Fri, 24 Jun 2022 15:55:33 +0200 Subject: [PATCH 06/10] cleanup --- .../config/common_instructions.json.in | 109 ++++++++++++------ .../config/config_cc_s17_direct_iq.json.in | 19 +++ .../openql_experiments/openql_helpers.py | 46 +++++--- pycqed/tests/openql/test_cqasm.py | 18 +++ 4 files changed, 140 insertions(+), 52 deletions(-) diff --git a/pycqed/measurement/openql_experiments/config/common_instructions.json.in b/pycqed/measurement/openql_experiments/config/common_instructions.json.in index 28fdd6b966..1c66adfcde 100644 --- a/pycqed/measurement/openql_experiments/config/common_instructions.json.in +++ b/pycqed/measurement/openql_experiments/config/common_instructions.json.in @@ -1,6 +1,11 @@ // File: common_instructions.json.in // notes: this file specifies commonalities between different setups for key "instructions" // see https://openql.readthedocs.io/en/latest/gen/reference_architectures.html#qutech-central-controller for documentation of this file +// We use the following conventions: +// - gate names starting with "_" are "private", they are not intended for direct use by the end user, but as target for decompositions +// - gate names starting with "__" are reserved, they should not be used for noemal operation (we use them for experimental features) +// - for key "cc/signal/value", we use a JSON string that is compatible with the LutMan definitions. OpenQL outputs a .map file +// containing a list of gates including said signal value, which should be used to configure the LutMans in the future. // author: Wouter Vlothuizen e.a. //{ @@ -123,6 +128,7 @@ }, // pi pulse 2nd excited state + // FIXME: unfortunate name choice, because in all other places the number denotes a rotation in degrees (especially in mw_lutman.py::inspire_mw_lutmap) "rx12": { "duration": @MW_DURATION@, "cc": { @@ -137,7 +143,6 @@ } }, - "square": { "duration": @MW_DURATION@, "cc": { @@ -670,6 +675,7 @@ "prototype": ["M:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_do_measure op(0)" } }, @@ -678,6 +684,7 @@ "prototype": ["M:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": [ "rx12 q[6];", "_do_measure q[6]" @@ -685,6 +692,46 @@ } }, + //************************************************************************************************************** + // additions for measurements using real time feedback, see 'CC-OpenQL-feedback-latency.pptx' + // FIXME: splitup into all components + //************************************************************************************************************** + + // wait for real-time results from UHFQA. The required time consists of: + // - the trigger latency of the UHF (which depends on #codewords) + // - the state declaration latency of the UHF + // - DIO cable and calibration delay + // NB: the actual duration of the measurement is accounted for in the 'measure' instruction + "_wait_uhfqa": { + "prototype": ["U:qubit"], + "duration": 720 + }, + + // retrieve the real-time results and initiate distributing them within the CC + "_dist_dsm": { + "prototype": ["U:qubit"], + "duration": 20, + "cc": { + // although we don't output anything, we still need to associate with the correct measurement instrument & group + "signal": [ + { + "type": "measure", + "operand_idx": 0, + "value": [] // don't generate output signal. This also triggers special behaviour to retrieve measurements in real-time (from OpenQL 0.10.3) + } + ] + } + }, + + // wait for DSM to finish, consists of: + // - time required for DSM data distribution to finish (60 ns for 3 UHFs operating in parallel) + // - extra time required to cater for latency differences between instruments (FIXME: create separate entry) + // depends on instruments and their settings, and dependency of condition that follows on instruments + "_wait_dsm": { + "prototype": ["U:qubit"], + "duration": 280 + }, + //************************************************************************************************************** // flux //************************************************************************************************************** @@ -866,32 +913,11 @@ // } // }, - // additions for measurements using real time feedback - "_wait_uhfqa": { - "prototype": ["U:qubit"], - "duration": 720 - }, - "_dist_dsm": { - "prototype": ["U:qubit"], - "duration": 20, - "cc": { - // although we don't output anything, we still need to associate with the correct measurement instrument & group - "signal": [ - { - "type": "measure", - "operand_idx": 0, - "value": [] // don't generate output signal. This also triggers special behaviour to retrieve measurements in real-time (from OpenQL 0.10.3) - } - ] - } - }, - "_wait_dsm": { - "prototype": ["U:qubit"], - "duration": 280 - }, - + //************************************************************************************************************** // additions for pragma/break // Require OpenQL < 0.10.1 (use cQASM afterwards) + //************************************************************************************************************** + "if_1_break": { "duration": 60, "cc": { @@ -917,25 +943,36 @@ //************************************************************************************************************** // Parameterized gate decompositions (test) + // Based on https://gitlab.com/qutech-sd/quantum-infinity/infinity-control/-/blob/enh/feature_updates/src/infinity/compiler/transmon_compiler.py::__process_rotation_angles + // - angles are multiples of 5.625 degrees + // - compatible with mw_lutman.py::inspire_mw_lutmap + // - gate name is 'int(angle)' + // - original does not exploit wrapping at 360 degrees to get nearest angle + // FIXME: original has 'real' parameter in radians "__rx": { "prototype": ["X:qubit", "L:int"], "duration": 0, "decomposition": { - "into": [ // FIXME: makes no real sense, should match gateset used by QI - "if (op(1) < 45) {", - " rx45 op(0)", + "when": "pre-sched", + "into": [ + "if (op(1) <= 2) {", // int(0*5.625 + 5.625/2) + " i op(0)", +// "} else if (op(1) <= 8) {", // int(1*5.625 + 5.625/2) +// " rx5 op(0)", + // FIXME: etc, also requires defining all rx* gates "} else {", - " rx90 op(0)", + " i op(0)", "}" ] } }, - // Randomized banchmarking (test) + // Randomized benchmarking (test) // Based on epstein_efficient_decomposition "__test_epstein": { "prototype": ["X:qubit", "R:int"], "duration": 0, "decomposition": { + "when": "pre-sched", // NB: to meet timing, the CC backend of OpenQL would need to implement a computed goto for this long if-tree // Alternatively, a binary tree could help improve timing "into": [ @@ -1018,6 +1055,7 @@ "prototype": ["X:qubit", "X:qubit", "R:int", "R:int"], "duration": 0, "decomposition": { + "when": "pre-sched", // FIXME: becomes sequential if op(0) and op(1) are handled by same sequencer (and also if not!) "into": [ " __test_epstein op(0), op(2)", @@ -1029,6 +1067,7 @@ "prototype": ["X:qubit", "X:qubit", "R:int", "R:int", "R:int", "R:int"], "duration": 0, "decomposition": { + "when": "pre-sched", // op(0): // op(1): // op(2): rnd range [0,24) @@ -1048,10 +1087,12 @@ // Experimental decomposition to Waveforms //************************************************************************************************************** + // just one random gate where we replace the "cc|signal" key by a decomposition into a 'wave' representation not unlike OpenPulse "__cz_sw_ne_park": { "prototype": ["Z:qubit", "Z:qubit", "I:qubit"], "duration": 0, //@FLUX_DURATION@, "decomposition": { + "when": "post-sched", "into": [ "__play op(0), \"flux\", {|\"type\": \"cz\", \"which\": \"SW\", \"cw\": 3|}", "__play op(1), \"flux\", {|\"type\": \"idle_z\", \"which\": \"NE\", \"cw\": 1|}", @@ -1059,10 +1100,7 @@ ] } }, - - - // FIXME: add duration - // FIXME: add decomposition key + // FIXME: add duration to 'play' // Native waveform gates: "__play": { @@ -1074,7 +1112,4 @@ ] } - - - // }, // end of "instructions" diff --git a/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in b/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in index e51dc509a1..eadba328ce 100644 --- a/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in +++ b/pycqed/measurement/openql_experiments/config/config_cc_s17_direct_iq.json.in @@ -354,6 +354,7 @@ // "prototype": ["U:qubit", "U:bit"], // "duration": 0, // "decomposition": { +// "when": "pre-sched", // "into": "measure op(0),op(1); _wait_uhfqa op(0); _dist_dsm op(0); _wait_dsm op(0)" // } // } @@ -365,6 +366,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_sw_ne_park q[8],q[10],q[11]" } }, @@ -372,6 +374,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[8],q[10]" } }, @@ -380,6 +383,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_se_nw_park q[8],q[11],q[10]" } }, @@ -387,6 +391,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[8],q[11]" } }, @@ -395,6 +400,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_sw_ne_park q[11],q[14],q[15]" } }, @@ -402,6 +408,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[11],q[14]" } }, @@ -410,6 +417,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_se_nw q[10],q[14]" } }, @@ -417,6 +425,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[10],q[14]" } }, @@ -425,6 +434,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_sw_ne_park q[9],q[11],q[12]" } }, @@ -432,6 +442,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[9],q[11]" } }, @@ -440,6 +451,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_se_nw_park q[9],q[12],q[11]" } }, @@ -447,6 +459,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[9],q[12]" } }, @@ -455,6 +468,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_se_nw_park q[11],q[15],q[14]" } }, @@ -462,6 +476,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[11],q[15]" } }, @@ -470,6 +485,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "_cz_sw_ne q[12],q[15]" } }, @@ -477,6 +493,7 @@ "prototype": ["Z:qubit", "Z:qubit"], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "cz q[12],q[15]" } }, @@ -488,6 +505,7 @@ "prototype": [], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "{ cz q[8],q[10] | cz q[9],q[11] }" // FIXME: in custom instruction '_cz_sw_ne_park q[8], q[10], q[11]': Signal conflict on instrument='flux_0', group=3, between '{type:idle_z,which:NE}' and '{type:park}' } }, @@ -495,6 +513,7 @@ "prototype": [], "duration": 0, "decomposition": { + "when": "pre-sched", "into": "{ cz q[10],q[8] | cz q[9],q[12] }" // NB: both CZs park q[11] } }, diff --git a/pycqed/measurement/openql_experiments/openql_helpers.py b/pycqed/measurement/openql_experiments/openql_helpers.py index 45b2e6cf0e..eb98f9eae6 100644 --- a/pycqed/measurement/openql_experiments/openql_helpers.py +++ b/pycqed/measurement/openql_experiments/openql_helpers.py @@ -665,25 +665,31 @@ def _configure_compiler( } ) - # decomposer for legacy decompositions (those defined in the "gate_decomposition" section) - # FIXME: comment incorrect, also decomposes new-style definitions - # see https://openql.readthedocs.io/en/latest/gen/reference_passes.html#instruction-decomposer + # perform legacy decompositions (those defined in the "gate_decomposition" section), see: + # - https://openql.readthedocs.io/en/latest/gen/reference_passes.html#instruction-decomposer + # - https://openql.readthedocs.io/en/latest/gen/reference_passes.html#predicate-key c.append_pass( 'dec.Instructions', - # NB: don't change the name 'legacy', see: - # - https://openql.readthedocs.io/en/latest/gen/reference_passes.html#instruction-decomposer - # - https://openql.readthedocs.io/en/latest/gen/reference_passes.html#predicate-key - 'legacy', - ) - else: # FIXME: experimental. Also decompose API input to allow use of new style decompositions - c.append_pass( - 'dec.Instructions', - # NB: don't change the name 'legacy', see: - # - https://openql.readthedocs.io/en/latest/gen/reference_passes.html#instruction-decomposer - # - https://openql.readthedocs.io/en/latest/gen/reference_passes.html#predicate-key - 'legacy', + 'dec_legacy', + { + 'predicate_key': 'name', + 'predicate_value': 'legacy' + } ) + else: # API input, note that legacy decompositions are applied on the fly by the API + pass + + # perform new-style decompositions, pre-scheduling + c.append_pass( + 'dec.Instructions', + 'dec_pre_sched', + { + 'predicate_key': 'when', + 'predicate_value': 'pre-sched' + } + ) + # report the initial qasm c.append_pass( 'io.cqasm.Report', @@ -724,6 +730,16 @@ def _configure_compiler( } ) + # perform new-style decompositions, post-scheduling + c.append_pass( + 'dec.Instructions', + 'dec_post_sched', + { + 'predicate_key': 'when', + 'predicate_value': 'post-sched' + } + ) + # report scheduled qasm c.append_pass( 'io.cqasm.Report', diff --git a/pycqed/tests/openql/test_cqasm.py b/pycqed/tests/openql/test_cqasm.py index 7f85877e12..96272f06f1 100644 --- a/pycqed/tests/openql/test_cqasm.py +++ b/pycqed/tests/openql/test_cqasm.py @@ -193,6 +193,24 @@ def test_decompose_measure_specialized(self): p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above p.compile_cqasm(src) + @unittest.skip('fails in backend, as expected') + def test_decompose_waveforms(self): + name = f'test_decompose_waveforms' + src = f""" + # Note: file generated by {__file__}::test_decompose_waveforms + # File: {name}.cq + # Purpose: test decomposing into 'waveform' representation + + version 1.2 + + pragma @ql.name("{name}") # set the name of generated files + + __cz_sw_ne_park q[0],q[1],q[2] + """ + + p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above + p.compile_cqasm(src) + # FIXME: not cqasm, move def test_decompose_measure_specialized_api(self): p = OqlProgram("test_decompose_measure_specialized_api", str(platf_cfg_path)) From 1a7f6ef0f052c99896088664c17600e708af9b3b Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Mon, 4 Jul 2022 09:50:28 +0200 Subject: [PATCH 07/10] cleanup --- .../meta_instrument/HAL_Device.py | 168 +++++++++--------- .../config/common_instructions.json.in | 6 +- pycqed/tests/openql/test_cqasm.py | 6 + 3 files changed, 93 insertions(+), 87 deletions(-) diff --git a/pycqed/instrument_drivers/meta_instrument/HAL_Device.py b/pycqed/instrument_drivers/meta_instrument/HAL_Device.py index 866f15a505..e335903d83 100644 --- a/pycqed/instrument_drivers/meta_instrument/HAL_Device.py +++ b/pycqed/instrument_drivers/meta_instrument/HAL_Device.py @@ -599,7 +599,7 @@ def measure_parity_check_flux_dance( else: log.warning(f"Target qubit {target_qubits[0]} not X or Z!") - # if ramsey_qubits is given as list of qubit names, + # if ramsey_qubits is given as list of qubit names, # only those will be used and converted to qubit numbers. # if ramsey_qubits is given as boolean, # all ancillas that are not part of the parity check will be ramseyd @@ -611,18 +611,18 @@ def measure_parity_check_flux_dance( log.warning(f"Ramsey qubit {qb} already given as ancilla qubit!") Q_idxs_ramsey += [self.find_instrument(qb).cfg_qubit_nr()] - Q_idxs_target = [] + Q_idxs_target = [] for i,target_qubit in enumerate(target_qubits): log.info(f"Parity {target_qubit} - {control_qubits}, flux dance steps {flux_dance_steps}") Q_idxs_target += [self.find_instrument(target_qubit).cfg_qubit_nr()] # filter control qubits based on control_cases_to_measure, # then the cases will be created based on the filtered control qubits - Q_idxs_control = [] + Q_idxs_control = [] if not control_cases_to_measure: # if cases are not given, measure all cases for all control qubits - control_qubits_by_case = control_qubits - Q_idxs_control += [self.find_instrument(Q).cfg_qubit_nr() for Q in control_qubits_by_case] + control_qubits_by_case = control_qubits + Q_idxs_control += [self.find_instrument(Q).cfg_qubit_nr() for Q in control_qubits_by_case] cases = ['{:0{}b}'.format(i, len(Q_idxs_control)) for i in range(2**len(Q_idxs_control))] else: # if cases are given, prepare and measure only them @@ -633,14 +633,14 @@ def measure_parity_check_flux_dance( control_qubits_by_case += [control_qubits[i] for i,c in enumerate(case) \ if c == '1' and control_qubits[i] not in control_qubits_by_case] #control_qubits_by_case += [control_qubits[i] for i,c in enumerate(case) if c == '1'] - + # sort selected control qubits according to readout (feedline) order # qb_ro_order = np.sum([ list(self._acq_ch_map[key].keys()) for key in self._acq_ch_map.keys()], dtype=object) # dqb_ro_order = np.array(qb_ro_order, dtype=str)[[qb[0] == 'D' for qb in qb_ro_order]] control_qubits_by_case = [x for x,_ in sorted(zip(control_qubits_by_case, control_qubits))] - + Q_idxs_control += [self.find_instrument(Q).cfg_qubit_nr() for Q in control_qubits_by_case] - cases = control_cases_to_measure + cases = control_cases_to_measure # for separate preparation of parking qubits in 1, used to study parking if parking_qubits: @@ -659,9 +659,9 @@ def measure_parity_check_flux_dance( # MW preparation for qb in all_qubits: mw_lutman = self.find_instrument(qb).instr_LutMan_MW.get_instr() - # check the lutman of the target, control and parking qubits for cw_27, + # check the lutman of the target, control and parking qubits for cw_27, # which is needed for refocusing, case preparation, and preparation in 1 (respectively) - # and prepare if necessary + # and prepare if necessary xm180_dict = {"name": "rXm180", "theta": -180, "phi": 0, "type": "ge"} if mw_lutman.LutMap().get(27) != xm180_dict: log.warning(f"{mw_lutman.name} does not have refocusing pulse, overriding `cw_27` ...") @@ -680,14 +680,14 @@ def measure_parity_check_flux_dance( if prepare_for_timedomain: # Take care of readout order (by feedline/UHF) if self.qubits_by_feedline(): - all_qubits = sorted(all_qubits, + all_qubits = sorted(all_qubits, key=lambda x: [i for i, feedline in enumerate(self.qubits_by_feedline()) \ if x in feedline]) log.info(f"Sorted qubits for readout preparation: {all_qubits}") else: log.warning("Qubit order by feedline in `self.qubits_by_feedline()` parameter is not set, " + "readout will be prepared in order of given qubits which can lead to errors!") - + self.prepare_for_timedomain(qubits=all_qubits) # These are hardcoded angles in the mw_lutman for the AWG8 @@ -696,7 +696,7 @@ def measure_parity_check_flux_dance( # prepare flux codeword list according to given step numbers # will be programmed in order of the list, but scheduled in parallel (if possible) - + if refocusing: flux_cw_list = [flux_codeword + '_refocus' + f'_{step}' for step in flux_dance_steps] @@ -746,7 +746,7 @@ def measure_parity_check_flux_dance( return a.result # a = ma2.Parity_Check_Analysis( - # label=label, + # label=label, # target_qubit=target_qubits[0], # extract_only=not plotting, # analyze_parity_model=analyze_parity_model @@ -757,7 +757,7 @@ def measure_parity_check_flux_dance( # if analyze_parity_model: # model_errors = a.proc_data_dict['quantities_of_interest']['parity_model']['model_errors'] # model_terms = a.proc_data_dict['quantities_of_interest']['parity_model']['model_terms'] - # # this return structure is necessary to use this as a detector function + # # this return structure is necessary to use this as a detector function # # for higher level calibration routines # result = {**result, # 'model_errors': model_errors, @@ -838,20 +838,20 @@ def measure_parity_check_fidelity( all_qubits = target_qubits + control_qubits # MW preparation - Q_idxs_control = [] + Q_idxs_control = [] for qb in control_qubits: - Q_idxs_control += [self.find_instrument(qb).cfg_qubit_nr()] + Q_idxs_control += [self.find_instrument(qb).cfg_qubit_nr()] mw_lutman = self.find_instrument(qb).instr_LutMan_MW.get_instr() - # check the lutman of the target, control and parking qubits for cw_27, + # check the lutman of the target, control and parking qubits for cw_27, # which is needed for refocusing, case preparation, and preparation in 1 (respectively) - # and prepare if necessary + # and prepare if necessary xm180_dict = {"name": "rXm180", "theta": -180, "phi": 0, "type": "ge"} if mw_lutman.LutMap().get(27) != xm180_dict: log.warning(f"{mw_lutman.name} does not have refocusing pulse, overriding `cw_27` ...") mw_lutman.LutMap()[27] = xm180_dict mw_lutman.load_waveform_onto_AWG_lookuptable(27, regenerate_waveforms=True) - Q_idxs_target = [] + Q_idxs_target = [] for i,ancilla in enumerate(target_qubits): log.info(f"Parity check fidelity {ancilla} - {control_qubits}") Q_idxs_target += [self.find_instrument(ancilla).cfg_qubit_nr()] @@ -882,7 +882,7 @@ def measure_parity_check_fidelity( if prepare_for_timedomain: # Take care of readout order (by feedline/UHF) if self.qubits_by_feedline(): - all_qubits = sorted(all_qubits, + all_qubits = sorted(all_qubits, key=lambda x: [i for i, feedline in enumerate(self.qubits_by_feedline()) \ if x in feedline]) log.info(f"Sorted qubits for readout preparation: {all_qubits}") @@ -917,10 +917,10 @@ def measure_parity_check_fidelity( s = swf.OpenQL_Sweep(openql_program=p, CCL=self.instr_CC.get_instr()) d = self.get_int_logging_detector( - qubits=target_qubits+control_qubits, + qubits=target_qubits+control_qubits, result_logging_mode=result_logging_mode ) - shots_per_meas = int(np.floor(np.min([shots_per_meas, nr_shots]) / len(cases)) + shots_per_meas = int(np.floor(np.min([shots_per_meas, nr_shots]) / len(cases)) * len(cases) ) d.set_child_attr("nr_shots", shots_per_meas) @@ -957,8 +957,8 @@ def measure_sandia_parity_benchmark(self, # RO preparation (assign res_combinations) ########################################### RO_lms = np.unique([self.find_instrument(q).instr_LutMan_RO() for q in all_qubits]) - qubit_RO_lm = { self.find_instrument(q).cfg_qubit_nr() : - (self.find_instrument(q).name, + qubit_RO_lm = { self.find_instrument(q).cfg_qubit_nr() : + (self.find_instrument(q).name, self.find_instrument(q).instr_LutMan_RO()) for q in all_qubits } main_qubits = [] exception_qubits = [] @@ -1005,7 +1005,7 @@ def measure_sandia_parity_benchmark(self, MC.run(f"Sandia_parity_benchmark_{ancilla_qubit}_{data_qubits[0]}_{data_qubits[1]}_{data_qubits[2]}_{data_qubits[3]}") ma2.pba.Sandia_parity_benchmark(label='Sandia', - ancilla_qubit=ancilla_qubit, + ancilla_qubit=ancilla_qubit, data_qubits=data_qubits, exception_qubits=exception_qubits) @@ -1030,8 +1030,8 @@ def measure_weight4_parity_tomography( # RO preparation (assign res_combinations) ########################################### RO_lms = np.unique([self.find_instrument(q).instr_LutMan_RO() for q in all_qubits]) - qubit_RO_lm = { self.find_instrument(q).cfg_qubit_nr() : - (self.find_instrument(q).name, + qubit_RO_lm = { self.find_instrument(q).cfg_qubit_nr() : + (self.find_instrument(q).name, self.find_instrument(q).instr_LutMan_RO()) for q in all_qubits } main_qubits = [] exception_qubits = [] @@ -1062,7 +1062,7 @@ def measure_weight4_parity_tomography( ro_lm = self.find_instrument(lm) ro_lm.resonator_combinations(res_combs[lm]) ro_lm.load_DIO_triggered_sequence_onto_UHFQC() - + p = mqo.Weight_4_parity_tomography( Q_anc=ancilla_idx, Q_D1=data_idxs[0], @@ -1086,7 +1086,7 @@ def measure_weight4_parity_tomography( MC.soft_avg(1) MC.live_plot_enabled(False) MC.set_sweep_function(s) - MC.set_sweep_points(np.arange(int(uhfqc_max_avg/readouts_per_round) + MC.set_sweep_points(np.arange(int(uhfqc_max_avg/readouts_per_round) * readouts_per_round * repetitions)) MC.set_detector_function(d) MC.run(f'Weight_4_parity_tomography_{ancilla_qubit}_{data_qubits}_sim-msmt-{sim_measurement}_{label}') @@ -1119,7 +1119,7 @@ def measure_phase_corrections( phase_updates = dict.fromkeys([pair[0] for pair in pairs]) for i,pair in enumerate(pairs): phase_updates[pair[0]] = a[f"pair_{i}_phi_0_a"] - + if measure_switched_target: a = self.measure_conditional_oscillation( pairs=[pair[::-1] for pair in pairs], @@ -1803,7 +1803,7 @@ def measure_transients( def measure_msmt_induced_dephasing( self, - meas_qubit: str, + meas_qubit: str, target_qubits: list, measurement_time_ns: int, echo_times: list = None, @@ -1822,8 +1822,8 @@ def measure_msmt_induced_dephasing( # RO preparation (assign res_combinations) ########################################### RO_lms = np.unique([self.find_instrument(q).instr_LutMan_RO() for q in all_qubits]) - qubit_RO_lm = { self.find_instrument(q).cfg_qubit_nr() : - (self.find_instrument(q).name, + qubit_RO_lm = { self.find_instrument(q).cfg_qubit_nr() : + (self.find_instrument(q).name, self.find_instrument(q).instr_LutMan_RO()) for q in all_qubits } main_qubits = [] exception_qubits = [] @@ -1857,8 +1857,8 @@ def measure_msmt_induced_dephasing( assert echo_phases != None for i, q in enumerate(target_qubits): mw_lm = self.find_instrument(f'MW_lutman_{q}') - print(mw_lm.name) - mw_lm.LutMap()[30] = {'name': 'rEcho', 'theta': 180, + print(mw_lm.name) + mw_lm.LutMap()[30] = {'name': 'rEcho', 'theta': 180, 'phi': echo_phases[i], 'type': 'ge'} mw_lm.load_phase_pulses_to_AWG_lookuptable() @@ -1883,7 +1883,7 @@ def measure_msmt_induced_dephasing( MC.soft_avg(1) MC.live_plot_enabled(True) MC.set_sweep_function(s) - sw_pts = np.concatenate((np.repeat(np.arange(0, 360, 20), 6), + sw_pts = np.concatenate((np.repeat(np.arange(0, 360, 20), 6), np.array([360, 361, 362, 364]))) MC.set_sweep_points(sw_pts) MC.set_detector_function(d) @@ -2410,32 +2410,31 @@ def measure_cryoscope( for q in qubits: assert q in self.qubits() - + Q_idxs = [self.find_instrument(q).cfg_qubit_nr() for q in qubits] if prepare_for_timedomain: self.prepare_for_timedomain(qubits=qubits) if max_delay is None: - max_delay = 0 + max_delay = 0 else: max_delay = np.max(times) + 40e-9 Fl_lutmans = [self.find_instrument(q).instr_LutMan_Flux.get_instr() \ for q in qubits] + # determine sweep function and flux 'codeword' if waveform_name == "square": Sw_functions = [swf.FLsweep(lutman, lutman.sq_length, waveform_name="square") for lutman in Fl_lutmans] swfs = swf.multi_sweep_function(Sw_functions) flux_cw = "fl_cw_06" - elif waveform_name == "custom_wf": - Sw_functions = [swf.FLsweep(lutman, lutman.custom_wf_length, + Sw_functions = [swf.FLsweep(lutman, lutman.custom_wf_length, waveform_name="custom_wf") for lutman in Fl_lutmans] swfs = swf.multi_sweep_function(Sw_functions) flux_cw = "fl_cw_05" - else: raise ValueError( 'waveform_name "{}" should be either ' @@ -2475,6 +2474,7 @@ def measure_cryoscope( MC.set_detector_function(d) label = 'Cryoscope_{}_amps'.format('_'.join(qubits)) MC.run(label) + # Run analysis a = ma2.cv2.multi_qubit_cryoscope_analysis(label='Cryoscope', update_FIRs=update_FIRs) @@ -2562,8 +2562,8 @@ def measure_cryoscope_vs_amp( p = mqo.Cryoscope( q0idx, - buffer_time1=0, - buffer_time2=max_delay, + buffer_time1=0, # FIXME: unexpected argument + buffer_time2=max_delay, # FIXME: unexpected argument twoq_pair=twoq_pair, flux_cw=flux_cw, platf_cfg=self.cfg_openql_platform_fn()) @@ -3016,7 +3016,7 @@ def send_rb_tasks(pool_): # net_cliffords = [0, 3 * 24 + 3] # programs = [] - + # print('Generating {} RB programs'.format(nr_seeds)) # t0 = time.time() # for i in range(nr_seeds): @@ -5328,13 +5328,13 @@ def calibrate_parity_model_phases( """ Measures parity check as part of a flux dance for `B_sweep_points` different SNZ B values for each gate defined in `parity_check`. - Runs parity check model optimization analysis, which fits - a linear dependence of the parity check model phase error given - the measured error of each B value, to determine the B value required + Runs parity check model optimization analysis, which fits + a linear dependence of the parity check model phase error given + the measured error of each B value, to determine the B value required to achieve an error of zero. Args: - parity_check: + parity_check: List of qubits and gate directions which define the flux_lutmans to be used. Parking qubits are not used for this routine, and can be replaced with an empty list. Assumed format: [ [[ancilla_qubit]], [[data_qubit]], [[gate_direction]], [[parking_qubits]] ] @@ -5360,7 +5360,7 @@ def calibrate_parity_model_phases( flux_lm = self.find_instrument(f"flux_lm_{control_qubit[0]}") else: flux_lm = self.find_instrument(f"flux_lm_{target_qubit[0]}") - + old_B = flux_lm.parameters[f"vcz_amp_fine_{gate_direction[0]}"]() sweep_points = a_tools.get_values_around(old_B, range_frac=B_sweep_range_frac, num_points=B_sweep_n_points) @@ -5374,12 +5374,12 @@ def calibrate_parity_model_phases( old_weight_type = self.ro_acq_weight_type() self.ro_acq_digitized(False) self.ro_acq_weight_type('optimal') - + all_qubits = target_qubit + control_qubits_all if prepare_for_timedomain: # Take care of readout order (by feedline/UHF) if self.qubits_by_feedline(): - all_qubits = sorted(all_qubits, + all_qubits = sorted(all_qubits, key=lambda x: [i for i, feedline in enumerate(self.qubits_by_feedline()) \ if x in feedline]) log.info(f"Sorted qubits for readout preparation: {all_qubits}") @@ -5391,10 +5391,10 @@ def calibrate_parity_model_phases( # generate model terms to use for labels controls_qubits_sorted = [qb for qb in all_qubits if qb != target_qubit[0]] - control_combinations = [elem for k in range(1, len(controls_qubits_sorted)+1) + control_combinations = [elem for k in range(1, len(controls_qubits_sorted)+1) for elem in itt.combinations(controls_qubits_sorted, k)] model_terms = [target_qubit[0]] - model_terms += [ target_qubit[0] + ',' + qbs + model_terms += [ target_qubit[0] + ',' + qbs for qbs in [','.join(comb) for comb in control_combinations] ] d = det.Function_Detector( @@ -5415,7 +5415,7 @@ def calibrate_parity_model_phases( ) s = swf.FLsweep( - lm=flux_lm, + lm=flux_lm, par=flux_lm.parameters[f"vcz_amp_fine_{gate_direction[0]}"], waveform_name=f"cz_{gate_direction[0]}", upload_waveforms_always=True @@ -5442,7 +5442,7 @@ def calibrate_parity_model_phases( print(repr(e)) print(e.__traceback__) log.error(logging.traceback.format_exc()) - + # reset B! flux_lm.parameters[f"vcz_amp_fine_{gate_direction[0]}"](old_B) @@ -5495,7 +5495,7 @@ def calibrate_snz_fine_landscape( horizontal_calibration == True: Horizontal calibration mode, parity check will be optimized while whole flux dance specified by `flux_codeword` and `flux_dance_steps` is played. - + Args: Raises: @@ -5557,8 +5557,8 @@ def calibrate_snz_fine_landscape( 'extract_only': True, 'disable_metadata': True}, # TODO adapt for nested lists - value_names=[f'cost_function_val_{pair}', - f'delta_phi_{pair}', + value_names=[f'cost_function_val_{pair}', + f'delta_phi_{pair}', f'missing_fraction_{pair}'], result_keys=[f'cost_function_val_{pair}', f'delta_phi_{pair}', @@ -5576,18 +5576,18 @@ def calibrate_snz_fine_landscape( else: flux_lm = self.find_instrument(f"flux_lm_{pair[1]}") - # TODO: bypass waveform upload in sweep functions to save time by avoiding + # TODO: bypass waveform upload in sweep functions to save time by avoiding # repeated upload of the same parameters. # Waveforms can be updated and uploaded only in the detector function - # which should be enough since the detector function is called by the MC + # which should be enough since the detector function is called by the MC # only after new sweep function values are set. # But somehow this was not working during an initial test. - sweep_function_1 = swf.FLsweep(lm=flux_lm, + sweep_function_1 = swf.FLsweep(lm=flux_lm, par=flux_lm.parameters[f"vcz_amp_sq_{gate_direction}"], waveform_name=f"cz_{gate_direction}", # bypass_waveform_upload=True, - upload_waveforms_always=True) - sweep_function_2 = swf.FLsweep(lm=flux_lm, + upload_waveforms_always=True) + sweep_function_2 = swf.FLsweep(lm=flux_lm, par=flux_lm.parameters[f"vcz_amp_fine_{gate_direction}"], waveform_name=f"cz_{gate_direction}", # bypass_waveform_upload=True, @@ -5597,16 +5597,16 @@ def calibrate_snz_fine_landscape( log.info(f"Flux codeword: {flux_codeword}, flux dance steps: {flux_dance_steps}") if adaptive_target_cost is not None: - # target cost value can be computed by: + # target cost value can be computed by: # target_cost = cf.parity_check_cost( - # phase_diff=185, - # phase_weight=0.5, + # phase_diff=185, + # phase_weight=0.5, # missing_fraction=0.02) # convergence threshold strangely has to be given in loss function, not here - goal = lndm.mk_min_threshold_goal_func(max_pnts_beyond_threshold=2) + goal = lndm.mk_min_threshold_goal_func(max_pnts_beyond_threshold=2) else: goal = lndm.mk_minimization_goal_func() - + loss = lndm.mk_minimization_loss_func( max_no_improve_in_local=6, converge_below=adaptive_target_cost, @@ -5642,7 +5642,7 @@ def calibrate_snz_fine_landscape( log.info(f"Optimization result: {result['opt_res']}") log.info(f"A = {flux_lm.parameters[f'vcz_amp_sq_{gate_direction}']()}," f"B = {flux_lm.parameters[f'vcz_amp_fine_{gate_direction}']()}") - + if update: if horizontal_calibration: # Heatmap analysis currently doesn't work for msmt format of horizontal calibration @@ -5691,7 +5691,7 @@ def calibrate_snz_fine_landscape( self.measure_parity_check_flux_dance( target_qubits=[pair[0]], control_qubits=[pair[1]], - ramsey_qubits=ramsey_qubits, + ramsey_qubits=ramsey_qubits, flux_dance_steps=flux_dance_steps, flux_codeword=flux_codeword, prepare_for_timedomain=True, @@ -5710,7 +5710,7 @@ def calibrate_snz_fine_landscape( log.error(logging.traceback.format_exc()) def measure_vcz_A_B_landscape( - self, + self, Q0, Q1, A_ranges, @@ -5719,8 +5719,8 @@ def measure_vcz_A_B_landscape( Q_parks: list = None, flux_codeword: str = 'cz'): """ - Perform 2D sweep of amplitude and wave parameter while measuring - conditional phase and missing fraction via the "conditional + Perform 2D sweep of amplitude and wave parameter while measuring + conditional phase and missing fraction via the "conditional oscillation" experiment. Q0 : High frequency qubit(s). Can be given as single qubit or list. @@ -5740,7 +5740,7 @@ def measure_vcz_A_B_landscape( nested_MC = self.instr_nested_MC.get_instr() # get gate directions directions = [get_gate_directions(q0, q1) for q0, q1 in zip(Q0, Q1)] - + # Time-domain preparation # Prepare for time domain self.prepare_for_timedomain( @@ -5765,7 +5765,7 @@ def wrapper(Q0, Q1, extract_only, disable_metadata): a = self.measure_conditional_oscillation_multi( - pairs=[[Q0[i], Q1[i]] for i in range(len(Q0))], + pairs=[[Q0[i], Q1[i]] for i in range(len(Q0))], parked_qbs=Q_parks, flux_codeword=flux_codeword, prepare_for_timedomain=prepare_for_timedomain, @@ -5777,8 +5777,8 @@ def wrapper(Q0, Q1, for i in range(len(Q0)) } mf = { f'missing_fraction_{i+1}' : a[f'pair_{i+1}_missing_frac_a']\ for i in range(len(Q0)) } - return { **cp, **mf} - + return { **cp, **mf} + d = det.Function_Detector( wrapper, msmt_kw={'Q0' : Q0, 'Q1' : Q1, @@ -5816,7 +5816,7 @@ def wrapper(Q0, Q1, def measure_vcz_A_tmid_landscape( - self, + self, Q0, Q1, T_mids, @@ -5826,8 +5826,8 @@ def measure_vcz_A_tmid_landscape( Tp : float = None, flux_codeword: str = 'cz'): """ - Perform 2D sweep of amplitude and wave parameter while measuring - conditional phase and missing fraction via the "conditional + Perform 2D sweep of amplitude and wave parameter while measuring + conditional phase and missing fraction via the "conditional oscillation" experiment. Q0 : High frequency qubit(s). Can be given as single qubit or list. @@ -5879,7 +5879,7 @@ def wrapper(Q0, Q1, extract_only, disable_metadata): a = self.measure_conditional_oscillation_multi( - pairs=[[Q0[i], Q1[i]] for i in range(len(Q0))], + pairs=[[Q0[i], Q1[i]] for i in range(len(Q0))], parked_qbs=Q_parks, flux_codeword=flux_codeword, prepare_for_timedomain=prepare_for_timedomain, @@ -5891,7 +5891,7 @@ def wrapper(Q0, Q1, for i in range(len(Q0)) } mf = { f'missing_fraction_{i+1}' : a[f'pair_{i+1}_missing_frac_a']\ for i in range(len(Q0)) } - return { **cp, **mf} + return { **cp, **mf} d = det.Function_Detector( wrapper, @@ -5915,7 +5915,7 @@ def wrapper(Q0, Q1, n_points=A_points) swf2 = swf.flux_t_middle_sweep( fl_lm_tm = list(np.array([[Flux_lm_0[i], Flux_lm_1[i] ]\ - for i in range(len(Q0))]).flatten()), + for i in range(len(Q0))]).flatten()), fl_lm_park = Flux_lms_park, which_gate = list(np.array(directions).flatten()), t_pulse = Tp) diff --git a/pycqed/measurement/openql_experiments/config/common_instructions.json.in b/pycqed/measurement/openql_experiments/config/common_instructions.json.in index 1c66adfcde..1e8cfc2ea0 100644 --- a/pycqed/measurement/openql_experiments/config/common_instructions.json.in +++ b/pycqed/measurement/openql_experiments/config/common_instructions.json.in @@ -1087,7 +1087,7 @@ // Experimental decomposition to Waveforms //************************************************************************************************************** - // just one random gate where we replace the "cc|signal" key by a decomposition into a 'wave' representation not unlike OpenPulse + // just one random gate where we replace the "cc/signal" key by a decomposition into a 'wave' representation not unlike OpenPulse "__cz_sw_ne_park": { "prototype": ["Z:qubit", "Z:qubit", "I:qubit"], "duration": 0, //@FLUX_DURATION@, @@ -1106,8 +1106,8 @@ "__play": { "duration": @FLUX_DURATION@, // FIXME "prototype": [ - "Z:qubit", // qubit used as part of port - "L:string", // port part 2 + "Z:qubit", // qubit, used as part 1 of port + "L:string", // part 2 of port "L:json" // waveform ] } diff --git a/pycqed/tests/openql/test_cqasm.py b/pycqed/tests/openql/test_cqasm.py index 96272f06f1..b64aaa8c6a 100644 --- a/pycqed/tests/openql/test_cqasm.py +++ b/pycqed/tests/openql/test_cqasm.py @@ -206,6 +206,12 @@ def test_decompose_waveforms(self): pragma @ql.name("{name}") # set the name of generated files __cz_sw_ne_park q[0],q[1],q[2] + cond (b[0]) __cz_sw_ne_park q[0],q[1],q[2] + + # FIXME: other cond stuff, move + cond (b[0]) __test_epstein q[0],5 # FIXME: condition is lost + cond (b[0]) __rx q[0], 10 # FIXME: condition is lost, constant propagation not performed + """ p = OqlProgram(name, str(platf_cfg_path)) # NB: name must be identical to name set by "pragma @ql.name" above From 27cdfba07ab7d89084d1981f50053c2f2a2bea8a Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Mon, 28 Nov 2022 13:51:28 +0100 Subject: [PATCH 08/10] WIP --- examples/CC_examples/CC_run.py | 4 ++-- .../openql_experiments/config/common_instructions.json.in | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/CC_examples/CC_run.py b/examples/CC_examples/CC_run.py index 07b958f80b..a8fa3d1062 100755 --- a/examples/CC_examples/CC_run.py +++ b/examples/CC_examples/CC_run.py @@ -35,7 +35,7 @@ log.info('connecting to CC') cc = CC('cc', IPTransport(ip)) -cc.init() +#cc.init() for filename in filenames: log.info(f"uploading '{filename}' and starting CC") @@ -47,5 +47,5 @@ for i in range(err_cnt): print(cc.get_system_error()) -cc.print_event() +#cc.print_event() cc.print_status() diff --git a/pycqed/measurement/openql_experiments/config/common_instructions.json.in b/pycqed/measurement/openql_experiments/config/common_instructions.json.in index 1e8cfc2ea0..d6b1c94318 100644 --- a/pycqed/measurement/openql_experiments/config/common_instructions.json.in +++ b/pycqed/measurement/openql_experiments/config/common_instructions.json.in @@ -1090,7 +1090,7 @@ // just one random gate where we replace the "cc/signal" key by a decomposition into a 'wave' representation not unlike OpenPulse "__cz_sw_ne_park": { "prototype": ["Z:qubit", "Z:qubit", "I:qubit"], - "duration": 0, //@FLUX_DURATION@, + "duration": 0, //@FLUX_DURATION@, FIXME: must be set to schedule "decomposition": { "when": "post-sched", "into": [ @@ -1104,7 +1104,7 @@ // Native waveform gates: "__play": { - "duration": @FLUX_DURATION@, // FIXME + "duration": @FLUX_DURATION@, // FIXME: depends on gate "prototype": [ "Z:qubit", // qubit, used as part 1 of port "L:string", // part 2 of port From 1322e8de2976e707048171896f3504a8e1a2f35a Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Fri, 9 Dec 2022 14:54:17 +0100 Subject: [PATCH 09/10] documented misnomer --- pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py b/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py index dd34c58936..dae3a85972 100644 --- a/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py +++ b/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py @@ -154,6 +154,7 @@ def get_calibrate_dio_success(self, ccio: int) -> int: def get_calibrate_dio_read_index(self, ccio: int) -> int: return self._ask_int('QUTech:CCIO#:DIOIN:CALibrate:READINDEX?') + # FIXME: actually returns window size: margin = int((result-1)/2) def get_calibrate_dio_margin(self, ccio: int) -> int: return self._ask_int('QUTech:CCIO#:DIOIN:CALibrate:MARGIN?') From d9538f45c2371e9ada0a6c400feec189916c8253 Mon Sep 17 00:00:00 2001 From: Wouter Vlothuizen Date: Fri, 9 Dec 2022 15:04:03 +0100 Subject: [PATCH 10/10] added get_calibrate_dio_timing_window, corrected get_calibrate_dio_margin --- .../physical_instruments/QuTech/CCCore.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py b/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py index 3fe13ba0d5..69af7e4969 100644 --- a/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py +++ b/pycqed/instrument_drivers/physical_instruments/QuTech/CCCore.py @@ -157,9 +157,11 @@ def get_calibrate_dio_status(self, ccio: int) -> int: def get_calibrate_dio_read_index(self, ccio: int) -> int: return self._ask_int(f'QUTech:CCIO{ccio}:DIOIN:CALibrate:READINDEX?') - # FIXME: actually returns window size: margin = int((result-1)/2) def get_calibrate_dio_margin(self, ccio: int) -> int: - return self._ask_int(f'QUTech:CCIO{ccio}:DIOIN:CALibrate:MARGIN?') + return int( (self.get_calibrate_dio_timing_window(ccio)-1)/2) + + def get_calibrate_dio_timing_window(self, ccio: int) -> int: + return self._ask_int(f'QUTech:CCIO{ccio}:DIOIN:CALibrate:MARGIN?') # FIXME: CC actually returns window size def set_vsm_delay_rise(self, ccio: int, bit: int, cnt_in_833_ps_steps: int) -> None: self._transport.write(f'QUTech:CCIO{ccio}:VSMbit{bit}:RISEDELAY {cnt_in_833_ps_steps}')