Qaching#
- qache(*func, **kwargs)[source]#
This decorator allows you to mark a function as “reusable”. Reusable here means that the jasp expression of this function will be cached and reused in the next calls (if the function is called with the same signature).
A qached function therefore has to be traced by the Python interpreter only once and after that the function can be called without any Python-interpreter induced delay. This can significantly speed up the compilation process.
Using the
qachedecorator not only improves the compilation speed but also enables the compiler to speed up transformation processes.Warning
Two important rules apply to the
qachedecorator to adhere to the functional programming paradigm.It is illegal to have a qached function return a QuantumVariable that has been passed as an argument to the function.
It is illegal to modify traced attributes of QuantumVariables that have been passed as an argument to the function.
See the examples section for representatives of these cases.
- Parameters:
- funccallable
The function to be qached.
- Returns:
- qached_functioncallable
A function that will be traced on it’s first execution and retrieved from the cache in any other call.
Examples
We create a simple function that is qached. To simulate an expensive compilation task we insert a
time.sleepcommand.import time from qrisp import * from qrisp.jasp import qache @qache def inner_function(qv): h(qv[0]) cx(qv[0], qv[1]) res_bl = measure(qv[0]) # Simulate demanding compilation procedure by calling time.sleep(1) return res_bl def main(): a = QuantumVariable(2) b = QuantumFloat(2) bl_0 = inner_function(a) bl_1 = inner_function(b) bl_2 = inner_function(a) bl_3 = inner_function(b) return bl_0 & bl_1 & bl_2 & bl_3 # Measure the time required for tracing t0 = time.time() jaspr = make_jaspr(main)() print(time.time() - t0) # 2.0225703716278076
Even though
inner_functionhas been called 4 times, we only see a delay of 2 seconds. This is because the function has been called with two different quantum types, implying it has been traced twice and recalled from the cache twice. We take a look at the Jaspr.>>> print(jaspr) let inner_function = { lambda ; a:QuantumCircuit b:QubitArray. let c:Qubit = jasp.get_qubit b 0 d:QuantumCircuit = jasp.h a c e:Qubit = jasp.get_qubit b 1 f:QuantumCircuit = jasp.cx d c e g:QuantumCircuit h:bool[] = jasp.measure f c in (g, h) } in let inner_function1 = { lambda ; i:QuantumCircuit j:QubitArray k:i32[] l:bool[]. let m:Qubit = jasp.get_qubit j 0 n:QuantumCircuit = jasp.h i m o:Qubit = jasp.get_qubit j 1 p:QuantumCircuit = jasp.cx n m o q:QuantumCircuit r:bool[] = jasp.measure p m in (q, r) } in { lambda ; s:QuantumCircuit. let t:QuantumCircuit u:QubitArray = jasp.create_qubits s 2 v:QuantumCircuit w:QubitArray = jasp.create_qubits t 2 x:QuantumCircuit y:bool[] = pjit[name=inner_function jaxpr=inner_function] v u z:QuantumCircuit ba:bool[] = pjit[name=inner_function jaxpr=inner_function1] x w 0 False bb:QuantumCircuit bc:bool[] = pjit[name=inner_function jaxpr=inner_function] z u bd:QuantumCircuit be:bool[] = pjit[ name=inner_function jaxpr=inner_function1 ] bb w 0 False bf:bool[] = and y ba bg:bool[] = and bf bc bh:bool[] = and bg be bi:QuantumCircuit = jasp.reset bd u bj:QuantumCircuit = jasp.delete_qubits bi u in (bj, bh) }
As expected, we see three different function definitions:
The first one describes
inner_functioncalled with a QuantumVariable. For this kind of signature only theQubitArrayis required.The second one describes
inner_functioncalled with QuantumFloat. Additionally to theQubitArray, the.exponentand.signedattribute are also passed to the function.The third function definition is
outer_function, which calls the previously defined functions.
Illegal functions
We will now demonstrate what type of functions can not be qached.
@qache def inner_function(qv): h(qv[0]) return qv @jaspify def main(): qf_0 = QuantumFloat(2) qf_1 = inner_function(qf_0) return measure(qf_1) main() # Yields: Exception: Found parameter QuantumVariable within returned results
inner_functionreturns a QuantumVariable that has been passed as an argument and can therefore not be qached.The second case of an illegal functions is a function that tries to modify a traced attribute of a
QuantumVariablethat has been passed as an argument. A traced attribute is for instance theexponentattribute of QuantumFloat.@qache def inner_function(qf): qf.exponent += 1 @jaspify def main(): qf = QuantumFloat(2) inner_function(qf) main() # Yields: Exception: Found in-place parameter modification of QuantumVariable qf