question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ParamResolver is slow

See original GitHub issue

Reconstructing a circuit op-wise and replacing all parametrized ops with new ops containing parameter updates is 10-50x faster than using cirq.ParamResolver with sympy symbols…

Example code to reproduce:

from timeit import default_timer as timer
import numpy as np
import sympy
import cirq


def update_params(circuit, params):
    """Competitor method to cirq.ParamResolver."""
    new_op_tree = []
    for op, param in zip(circuit.all_operations(), params):
        new_op_tree.append(op.gate._with_exponent(param/np.pi)(*op.qubits))
    return cirq.Circuit.from_ops(new_op_tree)


trials = 100
for depth in [10, 15, 20]:
    sympy_circuit = cirq.Circuit.from_ops([cirq.Rx(sympy.Symbol(str(k)))(cirq.LineQubit(0)) for k in range(depth)])
    random_params = np.random.randn(trials, depth)
    # time twenty runs
    start = timer()
    for j in range(trials):
        resolver = dict(zip([str(k) for k in range(depth)], random_params[j]))
        wf1 = cirq.Simulator().simulate(sympy_circuit, param_resolver=resolver).final_state
    end = timer() - start
    print(f"{depth} parameters, {trials} trials using Sympy+ParamResolver: {end} seconds")

    start = timer()
    for j in range(trials):
        float_circuit = update_params(sympy_circuit, random_params[j])
        wf2 = cirq.Simulator().simulate(float_circuit).final_state
    end = timer() - start
    print(f"{depth} parameters, {trials} trials using reconstructed circuit: {end} seconds")

produced (cirq v0.5.0, Windows 10 + core i7 gen 7 processor)

>>> 10 parameters, 100 trials using Sympy+ParamResolver: 2.408036000095308 seconds
>>> 10 parameters, 100 trials using reconstructed circuit: 0.1671589999459684 seconds
>>> 15 parameters, 100 trials using Sympy+ParamResolver: 4.347879000008106 seconds
>>> 15 parameters, 100 trials using reconstructed circuit: 0.25207799999043345 seconds
>>> 20 parameters, 100 trials using Sympy+ParamResolver: 7.1194350000005215 seconds
>>> 20 parameters, 100 trials using reconstructed circuit: 0.31734399998094887 seconds

Some plots of how this scales with large numbers of parameters (generated from a different script using the same update_params method): image

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:17 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
dstrain115commented, Oct 22, 2019

I took a stab at short-circuiting sympy for common cases for PR #2394 . It does not help the above code as written, but, if flattened or if using XPowGate (which doesn’t add the “x/pi” formula), this speeds up the code significantly.

10 parameters, 100 trials using flattened circuit: 0.1600349259097129 seconds
10 parameters, 100 trials using xpow circuit: 0.17739228205755353 seconds
10 parameters, 100 trials using reconstructed circuit: 0.16374025191180408 seconds:
15 parameters, 100 trials using flattened circuit: 0.2257283239159733 seconds
15 parameters, 100 trials using xpow circuit: 0.2516175350174308 seconds
15 parameters, 100 trials using reconstructed circuit: 0.23388241999782622 seconds:
20 parameters, 100 trials using flattened circuit: 0.2913768459111452 seconds
20 parameters, 100 trials using xpow circuit: 0.32354101818054914 seconds
20 parameters, 100 trials using reconstructed circuit: 0.29962173686362803 seconds:

The changed code is below, for reference:

trials = 100
for depth in [10, 15, 20]:
    global sympy_circuit
    global resolver
    sympy_circuit1 = cirq.Circuit.from_ops([cirq.Rx(sympy.Symbol(str(k)))(cirq.LineQubit(0)) for k in range(depth)])
    sympy_circuit2 = cirq.Circuit.from_ops([cirq.XPowGate(exponent=sympy.Symbol(str(k)))(cirq.LineQubit(0)) for k in range(depth)])
    sympy_circuit, expr_map = cirq.flatten(sympy_circuit1)
    random_params = np.random.randn(trials, depth)
    resolver = expr_map.transform_params(dict(zip([str(k) for k in range(depth)], random_params[0])))
    # time twenty runs
    start = timer()
    for j in range(trials):
        wf = cirq.Simulator().simulate(sympy_circuit, param_resolver=resolver).final_state
    end = timer() - start
    print(f"{depth} parameters, {trials} trials using flattened circuit: {end} seconds")

    # time twenty runs
    start = timer()
    for j in range(trials):
        resolver = dict(zip([str(k) for k in range(depth)], random_params[j]))
        wf = cirq.Simulator().simulate(sympy_circuit2, param_resolver=resolver).final_state
    end = timer() - start
    print(f"{depth} parameters, {trials} trials using xpow circuit: {end} seconds")

    start = timer()
    for j in range(trials):
        float_circuit = update_params(sympy_circuit, random_params[j])
        wf2 = cirq.Simulator().simulate(float_circuit).final_state
    end = timer() - start
    print(f"{depth} parameters, {trials} trials using reconstructed circuit: {end} seconds:")

0reactions
aminjahanpourcommented, Jun 3, 2020

I modified the gate class to comply with Sympy:


    def _unitary_(self):
        return sympy.sin(self.theta) * sympy.eye(4) - 1j * sympy.cos(self.theta) * sympy.Array([
            [0, 1, 0, 1],
            [-1, 0, 1, 0],
            [0, 1, 0, -1],
            [1, 0, 1, 0]
        ])

but now I can not produce the circuit unitary:

    "%s has no attribute %s." % (self.__class__.__name__, attr))
AttributeError: MutableDenseMatrix has no attribute astype.

I guess I have to first deal with this issue before getting at the issue of speed. Not sure here is the right place to focus on this issue?

Read more comments on GitHub >

github_iconTop Results From Across the Web

cirq.ParamResolver - Google Quantum AI
Note that passing a formula to this resolver can be slow due to the underlying sympy library. For circuits relying on quick performance, ......
Read more >
vavr-io/vavr - Gitter
First you start out with a ParamResolver (resolves a parameter), then switch it ... @danieldietrich how do I read those results? how much...
Read more >
Query is slow when using parameters but fast when using literal
I have a query that runs against a pretty large table, I need to do a count on it. If I use a...
Read more >
Service Management
The test suite does not run noticeably slower with this mechanism enabled. ... Parameter values are resolved later by Service or ParamResolver classes....
Read more >
Source code for drf_yasg.openapi - drf-yasg - Read the Docs
... is EXTREMELY slow, replaced with plain raise raise AttributeError("object ... :type ref_or_obj: SwaggerDict or _Ref :param resolver: component resolver ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found