Skip to content

cirq.resolve_parameters is slow #6091

@rht

Description

@rht

Description of the issue

The usage context is to run hybrid variational circuit fast. For a small circuit of 2 qubits, consisting of ZZFeatureMap and RealAmplitude, I find cirq.resolve_parameters to be ~15x slower than if I were to reconstruct the circuit from scratch with concrete numbers replacing the parameters instead.

How to reproduce the issue

import time

import numpy as np
import cirq
import sympy


def make_cirq_circuit(
    num_qubits,
    circuit_params,
    qubits,
    cirq_input_params,
    cirq_weight_params,
):
    circuit = cirq.Circuit()
    # Qiskit's ZZFeatureMap
    zz_repetitions = 2
    for i in range(zz_repetitions):
        circuit.append([cirq.H(q) for q in qubits])
        circuit.append(
            [cirq.Z(qubits[i]) ** (2.0 * cirq_input_params[i] / np.pi)]
            for i in range(num_qubits)
        )
        circuit.append(cirq.CX(qubits[0], qubits[1]))
        circuit.append(
            cirq.Z(qubits[1])
            ** (
                (2.0 * (np.pi - cirq_input_params[0]) * (np.pi - cirq_input_params[1]))
                / np.pi
            )
        )
    # Qiskit's RealAmplitude
    count = 0
    for i in range(4):
        circuit.append(cirq.CX(qubits[0], qubits[1]))
        circuit.append(cirq.ry(cirq_weight_params[count * 2]).on(qubits[0]))
        circuit.append(cirq.ry(cirq_weight_params[count * 2 + 1]).on(qubits[1]))
        count += 1
    return circuit


num_qubits = 2
qubits = cirq.LineQubit.range(num_qubits)

# Prepare the parameterized circuit
cirq_input_params = [sympy.Symbol("x0"), sympy.Symbol("x1")]
cirq_weight_params = [sympy.Symbol(f"theta{i}") for i in range(8)]
circuit_params = cirq_input_params + cirq_weight_params
circuit = make_cirq_circuit(
    num_qubits,
    circuit_params,
    qubits,
    cirq_input_params,
    cirq_weight_params,
)

# Resolve params
np.random.seed(42)
p = {p: np.random.random() for p in circuit_params}
tic = time.time()
resolved_circuit = cirq.resolve_parameters(circuit, p)
print("Elapsed cirq.resolve_parameters:", round(time.time() - tic, 3))

# What if we instead construct the circuit from scratch.
cirq_input_params = [np.random.random() for i in range(2)]
cirq_weight_params = [np.random.random() for i in range(8)]
circuit_params = cirq_input_params + cirq_weight_params
tic = time.time()
make_cirq_circuit(
    num_qubits,
    circuit_params,
    qubits,
    cirq_input_params,
    cirq_weight_params,
)
print("Elapsed construct from scratch:", round(time.time() - tic, 3))

Result:

Elapsed cirq.resolve_parameters: 0.045
Elapsed construct from scratch: 0.003

Cirq version
You can get the cirq version by printing cirq.__version__. From the command line:

1.1.0

Metadata

Metadata

Assignees

Labels

area/parametersparameter resolution, parameterized gates, operationsarea/performancekind/bug-reportSomething doesn't seem to work.triage/acceptedA consensus emerged that this bug report, feature request, or other action should be worked on

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions