def test_serialisation(self): """Serialize/deserialize a graph with a node with a PyMigenBody. Notes ----- The content of the bodies depends on the environment, i.e. how the test is executed. For this reason we just compare the structure of the graph here. """ s = StateSaver(int) example_migen = TestMigen(tb_num_iter=2000, name='counter', lvl=logging.INFO, vcd_name="/workdir/TestMigen.vcd") with DeltaGraph() as graph: example_migen_out = example_migen.call(in1=40, in2=2) s.save_and_exit( adder(example_migen_out.out1, multiplier(example_migen_out.out2))) data, _ = serialize_graph(graph) self.assertEqual(type(data), bytes) g_capnp = deserialize_graph(data).to_dict() assert_capnp_content_types(self, g_capnp) with open(os.path.join(self.datapath, 'graph_with_migen_capnp.json'), 'r') as file: self.assertEqual(g_capnp, json.load(file))
def test_selection_exclusion_preference(self): @DeltaBlock(template=self.test_template, allow_const=False, tags=["func_4", "excluded, preferred"]) def func_4(a: int, b: int) -> Void: print("func_4") raise DeltaRuntimeExit with DeltaGraph() as graph: n = self.test_template.call(1, 2) # start on a body different form the desired n.select_body(preferred=["func_4"]) _, self.program = serialize_graph(graph) node_bodies, _, _ = generate_wiring(self.program, excluded_body_tags=["excluded"]) self.assertEqual(len(node_bodies), 1) asyncio.run(self.assert_tag_from_py_script(node_bodies[0], "func_1")) node_bodies, _, _ = generate_wiring(self.program, excluded_body_tags=["excluded"], preferred_body_tags=["preferred"]) self.assertEqual(len(node_bodies), 1) asyncio.run(self.assert_tag_from_py_script(node_bodies[0], "func_2"))
def test_node_serialisation_duplicate_bodies(self): """If two blocks share the same body only keep one copy.""" with DeltaGraph() as test_graph: self.func(2, 3) self.func(4, 5) _, prog = serialize_graph(test_graph) self.assertEqual(len(prog.bodies), 5) self.assertEqual(prog.nodes[2].bodies[0], prog.nodes[5].bodies[0])
def test_all_body_exclusion_error(self): with DeltaGraph() as graph: n = self.test_template.call(1, 2) _, self.program = serialize_graph(graph) with self.assertRaises(AttributeError): node_bodies, _, _ = generate_wiring( self.program, excluded_body_tags=["func_1", "func_2", "func_3"])
def test_const_exit(self): """DeltaRuntimeExit cannot be raised in constant nodes.""" with DeltaGraph() as test_graph: const_exit(a=5) _, program = serialize_graph(test_graph) with PythonatorEnv(program.bodies) as env: self.build_artifacts = env.pythonate( program.nodes[1], program.nodes[1].bodies[0] ) with self.assertRaises(ValueError): asyncio.run(self.build_artifacts["cpp"].data)
def test_no_select_excluded_node_body(self): with DeltaGraph() as graph: n = self.test_template.call(1, 2) # start on a body different form the desired n.select_body(preferred=["excluded"]) _, self.program = serialize_graph(graph) node_bodies, _, _ = generate_wiring(self.program, excluded_body_tags=["excluded"]) self.assertEqual(len(node_bodies), 1) asyncio.run(self.assert_tag_from_py_script(node_bodies[0], "func_1"))
def test_migen_node(self): with DeltaGraph() as test_graph: c1 = DUT1(tb_num_iter=2000, name='counter1').call(i1=return_1000()) print_then_exit(c1.o1) _, serialised = serialize_graph(test_graph) top_v = BuildArtifact( name=f"{serialised.nodes[1].name}", data=serialised.bodies[1].migen.verilog.encode("utf-8")) with VerilatorEnv() as env: build_artifacts = env.verilate(top_v) asyncio.run(self.assert_build_correct(build_artifacts))
def test_splitter_serialisation(self): """Splitter nodes should be added when serialising.""" @DeltaBlock(allow_const=False) def add(a: int, b: int) -> int: return a + b with DeltaGraph() as test_graph: a = add(2, 3) self.func(a, 4) self.func(a, 5) _, prog = serialize_graph(test_graph) splitter_body = dill.loads(prog.bodies[-1].python.dillImpl) self.assertEqual(type(splitter_body), PyFuncBody) self.assertEqual(len(prog.nodes), 8)
def test_qiskit_serialisation(self): """Test Qiskit nodes serialization/deserialization. """ with DeltaGraph() as test_graph: HardwareAbstractionLayerNode( QiskitQuantumSimulator(register_size=2)).accept_command( hal_command=0x4000000) data, _ = serialize_graph(test_graph) g_capnp = deserialize_graph(data) # Checking that we are investigating the right node. self.assertEqual(g_capnp.nodes[1].name.split("_")[0], "accept") body = g_capnp.bodies[1].python.dillImpl node = dill.loads(body) node.eval(hal_command=0x4000000)
def assert_correct_file_serialisation(self, files): _, prog = serialize_graph(self.graph, files=files) if len(files) == 0: self.assertEqual(prog.files, b'') else: with tempfile.TemporaryDirectory() as zip_dir: filename = os.path.join(zip_dir, "df_zip.zip") with open(filename, "wb") as df_zip: df_zip.write(prog.files) with zipfile.ZipFile(filename, "r") as df_zip: file_list = set([ file for pattern in files for file in glob.glob(pattern) ]) self.assertEqual(len(file_list), len(df_zip.namelist())) for file in file_list: self.assertIn(file, df_zip.namelist()) with open(file, "rb") as content: self.assertEqual(content.read(), df_zip.read(file))
def test_serialisation(self): """Serialize/deserialize a graph. .. note:: The content of the bodies depends on the environment, i.e. how the test is executed. For this reason we just compare the structure of the graph here. """ with DeltaGraph() as graph: self.func(40, 2) data, _ = serialize_graph(graph) self.assertEqual(type(data), bytes) g_capnp = deserialize_graph(data).to_dict() assert_capnp_content_types(self, g_capnp) with open(os.path.join(self.datapath, 'graph_capnp.json'), 'r') as file: self.assertEqual(g_capnp, json.load(file))
def test_template_node_capnp(self): """Test serialisation of nodes with no body. """ template = NodeTemplate(inputs=[('a', int), ('b', int)], outputs=int, name="temp-test") with DeltaGraph() as test_graph: template.call(a=1, b=2) data, _ = serialize_graph(test_graph) g_capnp = deserialize_graph(data) for n in g_capnp.nodes: if n.name.split("_")[1] == 'temp-test': node = n break self.assertEqual(node.name.split("_")[0], 'template') self.assertEqual(len(node.bodies), 0)
def test_pythonate(self): """Build artifacts and check the compiled code is correct.""" with DeltaGraph() as test_graph: print_then_exit( n=interactive_func.call(num=add(a=2, b=3), val=4, opt=4) ) _, program = serialize_graph(test_graph) for node in program.nodes: if "add" in node.name: with PythonatorEnv(program.bodies) as env: self.build_artifacts = env.pythonate(node, node.bodies[0]) asyncio.run(self.assert_build_correct("add")) elif "interactive" in node.name: with PythonatorEnv(program.bodies) as env: self.build_artifacts = env.pythonate(node, node.bodies[0]) asyncio.run(self.assert_build_correct("interactive"))
def test_node_serialisation(self): """Generate graph and check serialisation is correct.""" with DeltaGraph() as test_graph: self.func(2, 3) _, prog = serialize_graph(test_graph) self.assertEqual("_".join(prog.nodes[2].name.split("_")[:-1]), "add_print_exit") self.assertEqual(prog.nodes[2].bodies[0], 2) self.assertEqual(prog.nodes[2].inPorts[0].name, "a") self.assertEqual(dill.loads(prog.nodes[2].inPorts[0].type), as_delta_type(int)) self.assertEqual(prog.nodes[2].inPorts[0].optional, True) self.assertEqual(prog.nodes[2].inPorts[1].name, "b") self.assertEqual(dill.loads(prog.nodes[2].inPorts[1].type), as_delta_type(int)) self.assertEqual(prog.nodes[2].inPorts[1].optional, True) self.assertEqual(len(prog.nodes[2].inPorts), 2) self.assertEqual(len(prog.nodes[2].outPorts), 0) self.assertEqual(prog.bodies[2].python.dillImpl, test_graph.nodes[2].body.as_serialized) self.assertEqual(len(prog.graph), 2) self.assertEqual(prog.graph[0].srcNode, 0) self.assertEqual(prog.graph[0].srcOutPort, 0) self.assertEqual(prog.graph[0].destNode, 2) self.assertEqual(prog.graph[0].destInPort, 0) self.assertEqual(prog.graph[0].direct, False) self.assertEqual(prog.graph[1].srcNode, 1) self.assertEqual(prog.graph[1].srcOutPort, 0) self.assertEqual(prog.graph[1].destNode, 2) self.assertEqual(prog.graph[1].destInPort, 1) self.assertEqual(prog.graph[1].direct, False)
def test_multi_body_serialisation(self): """Tests a graph with a multi-body node is serialised and matches a target capnp file. """ with DeltaGraph() as graph: n1 = self.func(40, 2) @DeltaBlock(allow_const=False) def simple_add_2(a: DOptional(int), b: DOptional(int)): raise DeltaRuntimeExit n1.add_body(simple_add_2) data, _ = serialize_graph(graph) self.assertEqual(type(data), bytes) g_capnp = deserialize_graph(data).to_dict() assert_capnp_content_types(self, g_capnp) with open(os.path.join(self.datapath, 'graph_multibody_capnp.json'), 'r') as file: self.assertEqual(g_capnp, json.load(file))
def test_interactive_serialisation(self): """Interactive nodes have their own serialised body type. This is to distinguish their bodies from Python bodies, as they take different inputs. """ @Interactive(inputs=[('a', int), ('b', int)], outputs=Void) def add(node) -> int: a = node.receive('a') b = node.receive('b') print(a + b) raise DeltaRuntimeExit with DeltaGraph() as test_graph: a = add.call(a=2, b=3) _, prog = serialize_graph(test_graph) self.assertEqual(prog.bodies[2].which(), 'interactive') interactive_body = prog.bodies[2].interactive.dillImpl self.assertEqual(interactive_body, a.body.as_serialized)
def test_projectQ_serialisation(self): """Test ProjectQ nodes serialization/deserialization. ProjectQ can't be fully serialized, we need to exclude from dill the engine (C++ libraries). This test is to guarantee that when we deserialize everything works as expected. """ with DeltaGraph() as test_graph: HardwareAbstractionLayerNode( ProjectqQuantumSimulator(register_size=2)).accept_command( hal_command=0x4000000) data, _ = serialize_graph(test_graph) g_capnp = deserialize_graph(data) # Checking that we are investigating the right node. self.assertEqual(g_capnp.nodes[1].name.split("_")[0], "accept") body = g_capnp.bodies[1].python.dillImpl node = dill.loads(body) node.eval(hal_command=0x4000000)
def test_node_serialisation_multi_body_node(self): """If two blocks share the same body only keep one copy.""" with DeltaGraph() as test_graph: n1 = self.func(2, 3) @DeltaBlock(allow_const=False) def over_complex_add(a: DOptional(int), b: DOptional(int)): raise DeltaRuntimeExit @Interactive(inputs=[('a', DOptional(int)), ('b', DOptional(int))]) def broken_adder(node: RealNode): node.receive('a') node.receive('b') raise DeltaRuntimeExit n1.add_body(AMigenNode()) n1.add_body(over_complex_add) n1.add_body(OpCacher().cached_add) n1.add_body(broken_adder) _, prog = serialize_graph(test_graph) self.assertEqual(len(prog.nodes[2].bodies), 5)
build_repo + "/" + main_cpp_file) shutil.copy("/workdir/demos/deltaflow_on_artiq/" + sc_hal_hpp_file, build_repo + "/" + sc_hal_hpp_file) shutil.copy( "/workdir/demos/deltaflow_on_artiq/" + projectq_hal_hpp_file, build_repo + "/" + projectq_hal_hpp_file) shutil.copy("/workdir/demos/deltaflow_on_artiq/" + hal_py_file, build_repo + "/" + hal_py_file) except FileExistsError: pass graph, _ = rabi_demo.get_graph() dotdf_bytes, program = serialize_graph(graph, name=program_name) node_bodies, node_inits, wiring = generate_wiring(program) # write artifacts to build repository for build_artifact_name, build_artifact_data in wiring.items(): print(f"writing: {build_artifact_name} into {build_repo}") with open(build_repo + f"/{build_artifact_name}", "wb") as f: write(build_artifact_data, f) # write python bodies to build repository for py_build_artifact in node_bodies: print(f"py_build_artifact: {py_build_artifact}") print(f"py_build_artifact: {type(py_build_artifact)}") with open(build_repo + f"/{py_build_artifact.name}", "wb") as f: write(py_build_artifact, f)
def check_build(self, test_graph): """Build SystemC program and run tests.""" _, program = serialize_graph(test_graph) _, _, wiring = generate_wiring(program) asyncio.run(self.assert_build_correct(wiring, test_graph.name))
def assert_correct_reqs_serialisation(self, reqs): _, prog = serialize_graph(self.graph, requirements=reqs) reqs = set(reqs) self.assertEqual(len(prog.requirements), len(reqs)) for requirement in reqs: self.assertIn(requirement, prog.requirements)