def test_add_instruction_already_compiled(self) -> None: block = InstructionBlock() wf1 = DummyWaveform() wf2 = DummyWaveform() block.add_instruction_exec(wf1) block.compile_sequence() block.add_instruction_exec(wf2) sequence = block.compile_sequence() expected_sequence = [EXECInstruction(wf1), EXECInstruction(wf2), STOPInstruction()] self.assertEqual(expected_sequence, sequence)
def test_run_program(self): wf = DummyWaveform(duration=1.1, defined_channels={'A', 'B'}) block = InstructionBlock() block.add_instruction_meas([('m1', 0., 1.)]) block.add_instruction_exec(wf) awg1 = DummyAWG() awg2 = DummyAWG() awg3 = DummyAWG() dac1 = DummyDAC() dac2 = DummyDAC() setup = HardwareSetup() setup.set_channel('A', PlaybackChannel(awg1, 0)) setup.set_channel('B', MarkerChannel(awg2, 0)) setup.set_channel('C', MarkerChannel(awg3, 0)) setup.set_measurement('m1', MeasurementMask(dac1, 'DAC_1')) setup.set_measurement('m2', MeasurementMask(dac2, 'DAC_2')) class ProgStart: def __init__(self): self.was_started = False def __call__(self): self.was_started = True program_started = ProgStart() setup.register_program('test', block, run_callback=program_started) self.assertIsNone(awg1._armed) self.assertIsNone(awg2._armed) self.assertIsNone(awg3._armed) self.assertIsNone(dac1._armed_program) self.assertIsNone(dac2._armed_program) setup.run_program('test') self.assertEqual(awg1._armed, 'test') self.assertEqual(awg2._armed, 'test') self.assertIsNone(awg3._armed) self.assertEqual(dac1._armed_program, 'test') self.assertIsNone(dac2._armed_program) self.assertTrue(program_started.was_started)
def test_add_instruction_exec(self) -> None: block = InstructionBlock() expected_instructions = [] waveforms = [DummyWaveform(), DummyWaveform(), DummyWaveform()] LOOKUP = [0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 2, 2] for id in LOOKUP: waveform = waveforms[id] instruction = EXECInstruction(waveform) expected_instructions.append(instruction) block.add_instruction_exec(waveform) expected_compiled_instructions = expected_instructions.copy() expected_compiled_instructions.append(STOPInstruction()) self.__verify_block(block, expected_instructions, expected_compiled_instructions)
def test_add_instruction_exec(self) -> None: block = InstructionBlock() expected_instructions = [] waveforms = [DummyWaveform(), DummyWaveform(), DummyWaveform()] LOOKUP = [0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 2, 2] for id in LOOKUP: waveform = waveforms[id] instruction = EXECInstruction(waveform) expected_instructions.append(instruction) block.add_instruction_exec(waveform) expected_compiled_instructions = expected_instructions.copy() expected_compiled_instructions.append(STOPInstruction()) self.__verify_block(block, expected_instructions, expected_compiled_instructions, None)
def test_render(self) -> None: wf1 = DummyWaveform(duration=19) wf2 = DummyWaveform(duration=21) block = InstructionBlock() block.add_instruction_exec(wf1) block.add_instruction_exec(wf2) plotter = Plotter(sample_rate=0.5) times, voltages = plotter.render(block.compile_sequence()) wf1_expected = [([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], 0)] wf2_expected = [([20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40], 1)] expected_result = list(range(0, 41, 2)) self.assertEqual(wf1_expected, wf1.sample_calls) self.assertEqual(wf2_expected, wf2.sample_calls) self.assertEqual(expected_result, list(times)) self.assertEqual(expected_result, list(voltages))
def test_render(self) -> None: wf1 = DummyWaveform(duration=19) wf2 = DummyWaveform(duration=21) block = InstructionBlock() block.add_instruction_exec(wf1) block.add_instruction_exec(wf2) plotter = Plotter(sample_rate=0.5) times, voltages = plotter.render(block) wf1_expected = [([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], 0)] wf2_expected = [([20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40], 1)] expected_result = numpy.array([range(0, 41, 2)]) self.assertEqual(wf1_expected, wf1.sample_calls) self.assertEqual(wf2_expected, wf2.sample_calls) self.assertTrue(numpy.all(expected_result == times)) self.assertTrue(numpy.all(expected_result == voltages)) self.assertEqual(expected_result.shape, voltages.shape)
def test_remove_program(self): wf_1 = DummyWaveform(duration=1.1, defined_channels={'A', 'B'}) wf_2 = DummyWaveform(duration=1.1, defined_channels={'A', 'C'}) block_1 = InstructionBlock() block_2 = InstructionBlock() block_1.add_instruction_meas([('m1', 0., 1.)]) block_1.add_instruction_exec(wf_1) block_2.add_instruction_meas([('m2', 0., 1.)]) block_2.add_instruction_exec(wf_2) awg1 = DummyAWG() awg2 = DummyAWG() awg3 = DummyAWG() dac1 = DummyDAC() dac2 = DummyDAC() setup = HardwareSetup() setup.set_channel('A', PlaybackChannel(awg1, 0)) setup.set_channel('B', MarkerChannel(awg2, 0)) setup.set_channel('C', MarkerChannel(awg3, 0)) setup.set_measurement('m1', MeasurementMask(dac1, 'DAC_1')) setup.set_measurement('m2', MeasurementMask(dac2, 'DAC_2')) setup.register_program('test_1', block_1) setup.register_program('test_2', block_2) setup.arm_program('test_1') setup.remove_program('test_1') self.assertEqual(setup.registered_programs.keys(), {'test_2'}) self.assertIsNone(awg1._armed) self.assertIsNone(awg2._armed)
def test_render(self) -> None: wf1 = DummyWaveform(duration=19) wf2 = DummyWaveform(duration=21) block = InstructionBlock() block.add_instruction_exec(wf1) block.add_instruction_exec(wf2) wf1_expected = ('A', [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) wf2_expected = ('A', [x-19 for x in [20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40]]) wf1_output_array_len_expected = len(wf1_expected[1]) wf2_output_array_len_expected = len(wf2_expected[1]) wf1.sample_output = numpy.linspace(start=4, stop=5, num=len(wf1_expected[1])) wf2.sample_output = numpy.linspace(6, 7, num=len(wf2_expected[1])) expected_times = numpy.arange(start=0, stop=42, step=2) expected_result = numpy.concatenate((wf1.sample_output, wf2.sample_output)) times, voltages = render(block, sample_rate=0.5) self.assertEqual(len(wf1.sample_calls), 1) self.assertEqual(len(wf2.sample_calls), 1) self.assertEqual(wf1_expected[0], wf1.sample_calls[0][0]) self.assertEqual(wf2_expected[0], wf2.sample_calls[0][0]) numpy.testing.assert_almost_equal(wf1_expected[1], wf1.sample_calls[0][1]) numpy.testing.assert_almost_equal(wf2_expected[1], wf2.sample_calls[0][1]) self.assertEqual(wf1_output_array_len_expected, len(wf1.sample_calls[0][2])) self.assertEqual(wf2_output_array_len_expected, len(wf2.sample_calls[0][2])) self.assertEqual(voltages.keys(), dict(A=0).keys()) numpy.testing.assert_almost_equal(expected_times, times) numpy.testing.assert_almost_equal(expected_result, voltages['A']) self.assertEqual(expected_result.shape, voltages['A'].shape)
def test_multiple_nested_block_construction(self) -> None: main_block = InstructionBlock() blocks = [] waveforms = [DummyWaveform(), DummyWaveform(), DummyWaveform()] main_block.add_instruction_exec(waveforms[0]) block = InstructionBlock() trigger = Trigger() ip = InstructionPointer(block) main_block.add_instruction_cjmp(trigger, block) block.return_ip = InstructionPointer(main_block, len(main_block)) blocks.append(block) block = InstructionBlock() trigger = Trigger() ip = InstructionPointer(block) main_block.add_instruction_cjmp(trigger, block) block.return_ip = InstructionPointer(main_block, len(main_block)) blocks.append(block) WAVEFORM_LOOKUP = [[2, 2, 1, 1], [0, 1, 1, 0, 2, 1]] for i in [0, 1]: block = blocks[i] lookup = WAVEFORM_LOOKUP[i] for id in lookup: waveform = waveforms[id] block.add_instruction_exec(waveform) block = InstructionBlock() ip = InstructionPointer(block) blocks[0].add_instruction_cjmp(trigger, block) block.return_ip = InstructionPointer(blocks[0], len(blocks[0])) blocks.append(block) for id in [1, 2, 0, 2]: waveform = waveforms[id] block.add_instruction_exec(waveform) context = dict() immutable_block = ImmutableInstructionBlock(main_block, context) self.__verify_block(main_block, immutable_block, context.copy())
def get_two_chan_test_block(wfg=WaveformGenerator(2)): generate_waveform = wfg.generate_single_channel_waveform generate_multi_channel_waveform = wfg.generate_multi_channel_waveform loop_block11 = InstructionBlock() loop_block11.add_instruction_exec(generate_multi_channel_waveform()) loop_block1 = InstructionBlock() loop_block1.add_instruction_repj(5, ImmutableInstructionBlock(loop_block11)) loop_block21 = InstructionBlock() loop_block21.add_instruction_exec(generate_multi_channel_waveform()) loop_block21.add_instruction_exec(generate_multi_channel_waveform()) loop_block2 = InstructionBlock() loop_block2.add_instruction_repj(2, ImmutableInstructionBlock(loop_block21)) loop_block2.add_instruction_exec(generate_multi_channel_waveform()) loop_block3 = InstructionBlock() loop_block3.add_instruction_exec(generate_multi_channel_waveform()) loop_block3.add_instruction_exec(generate_multi_channel_waveform()) loop_block411 = InstructionBlock() loop_block411.add_instruction_exec(MultiChannelWaveform([generate_waveform('A')])) loop_block412 = InstructionBlock() loop_block412.add_instruction_exec(MultiChannelWaveform([generate_waveform('A')])) loop_block41 = InstructionBlock() loop_block41.add_instruction_repj(7, ImmutableInstructionBlock(loop_block411)) loop_block41.add_instruction_repj(8, ImmutableInstructionBlock(loop_block412)) loop_block421 = InstructionBlock() loop_block421.add_instruction_exec(MultiChannelWaveform([generate_waveform('B')])) loop_block422 = InstructionBlock() loop_block422.add_instruction_exec(MultiChannelWaveform([generate_waveform('B')])) loop_block42 = InstructionBlock() loop_block42.add_instruction_repj(10, ImmutableInstructionBlock(loop_block421)) loop_block42.add_instruction_repj(11, ImmutableInstructionBlock(loop_block422)) chan_block4A = InstructionBlock() chan_block4A.add_instruction_repj(6, ImmutableInstructionBlock(loop_block41)) chan_block4B = InstructionBlock() chan_block4B.add_instruction_repj(9, ImmutableInstructionBlock(loop_block42)) loop_block4 = InstructionBlock() loop_block4.add_instruction_chan({frozenset('A'): ImmutableInstructionBlock(chan_block4A), frozenset('B'): ImmutableInstructionBlock(chan_block4B)}) root_block = InstructionBlock() root_block.add_instruction_exec(generate_multi_channel_waveform()) root_block.add_instruction_repj(10, ImmutableInstructionBlock(loop_block1)) root_block.add_instruction_repj(17, ImmutableInstructionBlock(loop_block2)) root_block.add_instruction_repj(3, ImmutableInstructionBlock(loop_block3)) root_block.add_instruction_repj(4, ImmutableInstructionBlock(loop_block4)) return root_block
class MultiChannelTests(unittest.TestCase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) wf = DummyWaveform() self.descriptionA = \ """\ LOOP 1 times: ->EXEC {} 1 times ->EXEC {} 50 times ->LOOP 17 times: ->LOOP 2 times: ->EXEC {} 1 times ->EXEC {} 1 times ->EXEC {} 1 times ->LOOP 3 times: ->EXEC {} 1 times ->EXEC {} 1 times ->LOOP 24 times: ->EXEC {} 7 times ->EXEC {} 8 times""" self.descriptionB = \ """\ LOOP 1 times: ->EXEC {} 1 times ->EXEC {} 50 times ->LOOP 17 times: ->LOOP 2 times: ->EXEC {} 1 times ->EXEC {} 1 times ->EXEC {} 1 times ->LOOP 3 times: ->EXEC {} 1 times ->EXEC {} 1 times ->LOOP 36 times: ->EXEC {} 10 times ->EXEC {} 11 times""" def generate_waveform(channel): return DummyWaveform(sample_output=None, duration=None, defined_channels={channel}) def generate_multi_channel_waveform(): return MultiChannelWaveform([generate_waveform('A'), generate_waveform('B')]) self.loop_block11 = InstructionBlock() self.loop_block11.add_instruction_exec(generate_multi_channel_waveform()) self.loop_block1 = InstructionBlock() self.loop_block1.add_instruction_repj(5, ImmutableInstructionBlock(self.loop_block11)) self.loop_block21 = InstructionBlock() self.loop_block21.add_instruction_exec(generate_multi_channel_waveform()) self.loop_block21.add_instruction_exec(generate_multi_channel_waveform()) self.loop_block2 = InstructionBlock() self.loop_block2.add_instruction_repj(2, ImmutableInstructionBlock(self.loop_block21)) self.loop_block2.add_instruction_exec(generate_multi_channel_waveform()) self.loop_block3 = InstructionBlock() self.loop_block3.add_instruction_exec(generate_multi_channel_waveform()) self.loop_block3.add_instruction_exec(generate_multi_channel_waveform()) self.loop_block411 = InstructionBlock() self.loop_block411.add_instruction_exec(MultiChannelWaveform([generate_waveform('A')])) self.loop_block412 = InstructionBlock() self.loop_block412.add_instruction_exec(MultiChannelWaveform([generate_waveform('A')])) self.loop_block41 = InstructionBlock() self.loop_block41.add_instruction_repj(7, ImmutableInstructionBlock(self.loop_block411)) self.loop_block41.add_instruction_repj(8, ImmutableInstructionBlock(self.loop_block412)) self.loop_block421 = InstructionBlock() self.loop_block421.add_instruction_exec(MultiChannelWaveform([generate_waveform('B')])) self.loop_block422 = InstructionBlock() self.loop_block422.add_instruction_exec(MultiChannelWaveform([generate_waveform('B')])) self.loop_block42 = InstructionBlock() self.loop_block42.add_instruction_repj(10, ImmutableInstructionBlock(self.loop_block421)) self.loop_block42.add_instruction_repj(11, ImmutableInstructionBlock(self.loop_block422)) self.chan_block4A = InstructionBlock() self.chan_block4A.add_instruction_repj(6, ImmutableInstructionBlock(self.loop_block41)) self.chan_block4B = InstructionBlock() self.chan_block4B.add_instruction_repj(9, ImmutableInstructionBlock(self.loop_block42)) self.loop_block4 = InstructionBlock() self.loop_block4.add_instruction_chan({frozenset('A'): ImmutableInstructionBlock(self.chan_block4A), frozenset('B'): ImmutableInstructionBlock(self.chan_block4B)}) self.root_block = InstructionBlock() self.root_block.add_instruction_exec(generate_multi_channel_waveform()) self.root_block.add_instruction_repj(10, ImmutableInstructionBlock(self.loop_block1)) self.root_block.add_instruction_repj(17, ImmutableInstructionBlock(self.loop_block2)) self.root_block.add_instruction_repj(3, ImmutableInstructionBlock(self.loop_block3)) self.root_block.add_instruction_repj(4, ImmutableInstructionBlock(self.loop_block4)) self.maxDiff = None def get_mcp(self, channels): program = MultiChannelProgram(self.root_block, ['A', 'B']) return program[channels] def test_init(self): with self.assertRaises(ValueError): MultiChannelProgram(InstructionBlock()) mcp = MultiChannelProgram(self.root_block, ['A', 'B']) self.assertEqual(mcp.channels, {'A', 'B'}) with self.assertRaises(KeyError): mcp['C'] def test_via_repr(self): root_loopA = self.get_mcp('A') root_loopB = self.get_mcp('B') waveformsA = tuple(loop.waveform for loop in root_loopA.get_depth_first_iterator() if loop.is_leaf()) reprA = self.descriptionA.format(*waveformsA) reprB = self.descriptionB.format(*(loop.waveform for loop in root_loopB.get_depth_first_iterator() if loop.is_leaf())) self.assertEqual(root_loopA.__repr__(), reprA) self.assertEqual(root_loopB.__repr__(), reprB)
def test_nested_block_construction(self) -> None: main_block = InstructionBlock() expected_instructions = [[], [], [], []] expected_compiled_instructions = [[], [], [], []] blocks = [] waveforms = [DummyWaveform(), DummyWaveform(), DummyWaveform()] main_block.add_instruction_exec(waveforms[0]) expected_instructions[0].append(EXECInstruction(waveforms[0])) block = main_block.create_embedded_block() trigger = Trigger() main_block.add_instruction_cjmp(trigger, block) expected_instructions[0].append(CJMPInstruction(trigger, block, 0)) block.return_ip = InstructionPointer(main_block, len(main_block)) blocks.append(block) block = main_block.create_embedded_block() trigger = Trigger() main_block.add_instruction_cjmp(trigger, block) expected_instructions[0].append(CJMPInstruction(trigger, block, 0)) block.return_ip = InstructionPointer(main_block, len(main_block)) blocks.append(block) WAVEFORM_LOOKUP = [[2, 2, 1, 1],[0, 1, 1, 0, 2, 1]] for i in [0, 1]: block = blocks[i] lookup = WAVEFORM_LOOKUP[i] for id in lookup: waveform = waveforms[id] expected_instructions[i + 1].append(EXECInstruction(waveform)) block.add_instruction_exec(waveform) block = blocks[0].create_embedded_block() blocks[0].add_instruction_cjmp(trigger, block) expected_instructions[1].append(CJMPInstruction(trigger, block, 0)) block.return_ip = InstructionPointer(blocks[0], len(blocks[0])) blocks.append(block) for id in [1, 2, 0, 2]: waveform = waveforms[id] expected_instructions[3].append(EXECInstruction(waveform)) block.add_instruction_exec(waveform) for i in [0, 1, 2, 3]: expected_compiled_instructions[i] = expected_instructions[i].copy() expected_compiled_instructions[0].append(STOPInstruction()) for i in [0, 1, 2]: expected_compiled_instructions[i + 1].append(GOTOInstruction(blocks[i].return_ip.block, blocks[i].return_ip.offset)) positions = [0, None, None, None] positions[3] = len(expected_compiled_instructions[1]) expected_compiled_instructions[1].extend(expected_compiled_instructions[3]) for i in [1, 2]: positions[i] = len(expected_compiled_instructions[0]) expected_compiled_instructions[0].extend(expected_compiled_instructions[i]) positions[3] += positions[1] self.__verify_block(blocks[2], expected_instructions[3], expected_compiled_instructions[3]) self.__verify_block(blocks[1], expected_instructions[2], expected_compiled_instructions[2]) self.__verify_block(blocks[0], expected_instructions[1], expected_compiled_instructions[1]) self.__verify_block(main_block, expected_instructions[0], expected_compiled_instructions[0]) self.assertEqual(positions[3], blocks[2].get_start_address()) self.assertEqual(positions[2], blocks[1].get_start_address()) self.assertEqual(positions[1], blocks[0].get_start_address()) self.assertEqual(positions[0], main_block.get_start_address()) for instruction in main_block.instructions: if isinstance(instruction, GOTOInstruction) or isinstance(instruction, CJMPInstruction): self.assertIsInstance(instruction.target.get_absolute_address(), int)
def test_nested_block_construction(self) -> None: main_block = InstructionBlock() expected_instructions = [[], [], [], []] expected_compiled_instructions = [[], [], [], []] expected_return_ips = [None] blocks = [] waveforms = [DummyWaveform(), DummyWaveform(), DummyWaveform()] main_block.add_instruction_exec(waveforms[0]) expected_instructions[0].append(EXECInstruction(waveforms[0])) block = InstructionBlock() trigger = Trigger() ip = InstructionPointer(block) main_block.add_instruction_cjmp(trigger, block) expected_instructions[0].append(CJMPInstruction(trigger, ip)) block.return_ip = InstructionPointer(main_block, len(main_block)) expected_return_ips.append( InstructionPointer(main_block, len(main_block))) blocks.append(block) block = InstructionBlock() trigger = Trigger() ip = InstructionPointer(block) main_block.add_instruction_cjmp(trigger, block) expected_instructions[0].append(CJMPInstruction(trigger, ip)) block.return_ip = InstructionPointer(main_block, len(main_block)) expected_return_ips.append( InstructionPointer(main_block, len(main_block))) blocks.append(block) WAVEFORM_LOOKUP = [[2, 2, 1, 1], [0, 1, 1, 0, 2, 1]] for i in [0, 1]: block = blocks[i] lookup = WAVEFORM_LOOKUP[i] for id in lookup: waveform = waveforms[id] expected_instructions[i + 1].append(EXECInstruction(waveform)) block.add_instruction_exec(waveform) block = InstructionBlock() ip = InstructionPointer(block) blocks[0].add_instruction_cjmp(trigger, block) expected_instructions[1].append(CJMPInstruction(trigger, ip)) block.return_ip = InstructionPointer(blocks[0], len(blocks[0])) expected_return_ips.append( InstructionPointer(blocks[0], len(blocks[0]))) blocks.append(block) for id in [1, 2, 0, 2]: waveform = waveforms[id] expected_instructions[3].append(EXECInstruction(waveform)) block.add_instruction_exec(waveform) for i in [0, 1, 2, 3]: expected_compiled_instructions[i] = expected_instructions[i].copy() expected_compiled_instructions[0].append(STOPInstruction()) for i in [0, 1, 2]: expected_compiled_instructions[i + 1].append( GOTOInstruction(blocks[i].return_ip)) positions = [0, None, None, None] positions[3] = len(expected_compiled_instructions[1]) self.__verify_block(blocks[2], expected_instructions[3], expected_compiled_instructions[3], expected_return_ips[3]) self.__verify_block(blocks[1], expected_instructions[2], expected_compiled_instructions[2], expected_return_ips[2]) self.__verify_block(blocks[0], expected_instructions[1], expected_compiled_instructions[1], expected_return_ips[1]) self.__verify_block(main_block, expected_instructions[0], expected_compiled_instructions[0], expected_return_ips[0])