Package: tierkreis
tierkreisTierkreis is a higher-order dataflow graph program representation and runtime
designed for compositional, quantum-classical hybrid algorithms.For a detailed introduction read the paper:Tierkreis: a Dataflow Framework for Hybrid Quantum-Classical Computing.This repository contains the source for thetierkreispython package, and the
protocol buffer definitions for Tierkreis data types and gRPC services (in theprotosdirectory) which define the protocols for the system.The python package provides a complete development and testing evironment for writing and running Tierkreis program, and allows you to write extensions ("workers") in python. By implementing the gRPC services you can also implement runtimes and workers in other languages.Getting StartedTo install the python package run:pipinstalltierkreisThis package is pure python and is compatible with Python 3.10 and above. Tierkreis has a strong, static type system, and full automated type inference is available as an extension on supported platforms via thetypecheckoptional feature. To install that run:pipinstalltierkreis[typecheck]You can now build a graph (Tierkreis program), optionally type check it and execute it. The recommended environment for this is a Jupyter notebook (especially given some operations are async).First we need the runtime we are going to execute on and a handle to the primitive functions available on that runtime.
The python package comes with thePyRuntimewhich runs locally in your python environment.fromtierkreis.builderimportgraph,Namespace,Output,Inputfromtierkreis.pyruntimeimportPyRuntimecl=PyRuntime([])# empty list for no extra workerssig=awaitcl.get_signature()ns=Namespace(sig)# get a handle to all functionsprint(ns.iadd)print(ns.unpack_pair)The output shows the type signatures of the two functions we will use to add two integers together and unpack a pair. Note Tierkreis functions have named inputsandoutputs.iadd(a: Int, b: Int) -> (value: Int)
unpack_pair(pair: Pair[VarType(a), VarType(b)]) -> (first: VarType(a), second: VarType(b))BuildThe@graphdecorator allows you to build graphs using python functions.@graph()defsum_pair(pair:Input)->Output:first,second=ns.unpack_pair(pair)# tierkreis functions can have multiple outputsreturnOutput(ns.iadd(first,second))Calling the decorated function with no arguments (sum_pair()) returns aTierkreisGraph.VisualiseIn an Jupyter notebook this is immediately visualised, as long as you haveGraphvizinstalled. In a script you can write the image to file withrender_graph:fromtierkreisimportrender_graphrender_graph(sum_pair(),"filename","pdf")Type checkIf you have thetypecheckextension installed, you can replace@graphwith@graph(type_check_sig=sig), providing the signature retrived from the client as above, and the graph will be type checked when you call the building function. A graph is well-typed if type annotations can be inferred for every edge of the graph. If type check fails, the error message will try to indicate the location of your error.The type checked version of the graph above looks like:Run graphWe can now run the graph using the client set up earlier:awaitcl.run_graph(sum_pair(),pair=(1,2))The inputs to the graph are provided via keyword argument, and most of the time you can just provide python values that are auto converted. Here the tuple of integers is automatically converted to the Tierkreis typePair[Int, Int]. The output is given in Tierkreis form:{'value': IntValue(value=3)}ExamplesFor a more involved example seevariational.ipynbCustom workersWorkersare standalone servers which implement a set of functions which can connect to a Tierkreis runtime to add extra primitives.
They do this by implementing theworkergRPC service. Thetierkreispython package makes it easy to do this by taking care of all the server logic, and the conversion to and from Tierkreis data types. Note that workers are intended to be deployed as part of remote Tierkreis runtimes, but we can use the PyRuntime to test and develop them without any networking code.For example, we could define a custom function to sum a list:fromtierkreis.worker.namespaceimportNamespaceasWorkerNSfromtierkreis.builderimportConstroot=WorkerNS()custom_ns=root["custom"]@custom_ns.function()asyncdefsum_list(lst:list[int])->int:returnsum(lst)cl=PyRuntime([root])ns=Namespace(awaitcl.get_signature())["custom"]@graph()defrunsum()->Output:returnOutput(ns.sum_list(Const([1,2,3])))awaitcl.run_graph(runsum())