利用 Cirq 完成 qsim 模拟

2023-02-24 15:40:03 浏览数 (1)

量子计算能够将未来计算的方式进行根本上的改变,并能够为我们提供解决经典棘手问题的可能性。为了实现量子计算的全部潜力,目前较为主流的解决方法是通过搭建一台纠错量子计算机的方式来进行——虽然这是我们最终将要实现的目标,但受限于量子硬件方面的限制,现阶段想要实现还是较为困难的。所以模拟量子电路和模拟量子硬件的软件成为目前研究人员最为关注的方向。值得一提,近来在这一方向的进展还是取得了一定成果的。

为了帮助世界各地的研究人员和开发人员研究开发量子算法,谷歌于 2020 年推出了开源的量子电路模拟器 qsim。据谷歌所说,它的性能更高,使用方法更直观,更“像量子硬件”。qsim 可通过谷歌的量子编程框架 Cirq 来完成许多量子算法相关的工作。

1. qsim 简介

qsim 于2020年由谷歌推出,是一个用 C 编写的高性能全波函数模拟器,能够使用户在经典处理器上更有效地模拟量子电路。它利用门融合、AVX/FMA 矢量指令以及 OpenMP 的多线程来实现快速的电路模拟。它计算所有

2^n

状态向量的振幅,其中

n

是量子位数,从本质上讲,模拟器重复执行矩阵向量乘法。一个矩阵向量乘法对应于应用一个门。总运行时间与

g2^n

成正比,其中

g

是 2 个量子门的数量。

因为同为谷歌系的产品,所以 qsim 与 Cirq 完成了高度集成,我们可以在 Cirq 中使用 qsim,目前 qsim 可用于在 90 核 Intel Xeon 工作站上运行多达 40 个量子比特的模拟。

qsim 中包含的一些软件工具有量子编程框架 Cirq、研究示例库 ReCirq 以及特定应用库,比如用于量子化学的 OpenFermion 和用于量子机器学习的 TensorFlow Quantum。qsim 中增加的新功能,可以使量子电路模拟的性能和直观性更强,能够使模拟的噪声更复杂 。

2. 安装

qsim 库在 qsimcirq PyPI 软件包中为 Cirq 提供了一个 Python 接口。我们可以尝试使用 pip 的方式来安装它:

安装 Cirq 和 qsimcirq 软件包:

代码语言:javascript复制
try:
    import cirq
except ImportError:
    !pip install cirq --quiet
    import cirq

try:
    import qsimcirq
except ImportError:
    !pip install qsimcirq --quiet
    import qsimcirq

使用 qsim 模拟 Cirq 电路非常简单:只需像其他框架一样正常定义电路,然后创建一个QSimSimulator来执行模拟。这个对象能够实现 Cirq 的 simulator.py 接口,因此我们可以将它放到任何使用基本 Cirq 模拟器的地方。

3. 运行案例

完成安装步骤后,我们可以通过 Cirq 来完成一些 qsim 的具体操作案例了,可以看看以下的运行实例:

全状态矢量模拟

下面的例子,展示了 qsim 针对计算电路的最终状态向量所进行的优化方式:

代码语言:javascript复制
# Define qubits and a short circuit.
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(cirq.H(q0), cirq.CX(q0, q1))
print("Circuit:")
print(circuit)
print()

# Simulate the circuit with Cirq and return the full state vector.
print('Cirq results:')
cirq_simulator = cirq.Simulator()
cirq_results = cirq_simulator.simulate(circuit)
print(cirq_results)
print()

# Simulate the circuit with qsim and return the full state vector.
print('qsim results:')
qsim_simulator = qsimcirq.QSimSimulator()
qsim_results = qsim_simulator.simulate(circuit)
print(qsim_results)

输出结果为:

代码语言:javascript复制
Circuit:
0: ───H───@───
          │
1: ───────X───

Cirq results:
measurements: (no measurements)

qubits: (cirq.LineQubit(0), cirq.LineQubit(1))
output vector: 0.707|00⟩   0.707|11⟩

phase:
output vector: |⟩

qsim results:
measurements: (no measurements)

qubits: (cirq.LineQubit(0), cirq.LineQubit(1))
output vector: 0.707|00⟩   0.707|11⟩

要从这个状态中进行采样,我们可以调用 Cirq 中的 sample_state_vector 来完成。

代码语言:javascript复制
samples = cirq.sample_state_vector(
    qsim_results.state_vector(), indices=[0, 1], repetitions=10)
print(samples)

结果输出为:

代码语言:javascript复制
[[0 0]
 [1 1]
 [1 1]
 [1 1]
 [1 1]
 [0 0]
 [0 0]
 [0 0]
 [0 0]
 [1 1]]

测量采样

qsim还支持从用户定义的测量门取样。

代码语言:javascript复制
# Define a circuit with measurements.
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
    cirq.H(q0), cirq.X(q1), cirq.CX(q0, q1),
    cirq.measure(q0, key='qubit_0'),
    cirq.measure(q1, key='qubit_1'),
)
print("Circuit:")
print(circuit)
print()

# Simulate the circuit with Cirq and return just the measurement values.
print('Cirq results:')
cirq_simulator = cirq.Simulator()
cirq_results = cirq_simulator.run(circuit, repetitions=5)
print(cirq_results)
print()

# Simulate the circuit with qsim and return just the measurement values.
print('qsim results:')
qsim_simulator = qsimcirq.QSimSimulator()
qsim_results = qsim_simulator.run(circuit, repetitions=5)
print(qsim_results)

最终输入的结果为:

代码语言:javascript复制
Circuit:
0: ───H───@───M('qubit_0')───
          │
1: ───X───X───M('qubit_1')───

Cirq results:
qubit_0=01000
qubit_1=10111

qsim results:
qubit_0=00001
qubit_1=11110

上面案例中的警告显示出了 simulaterun 这两种方法间的重要区别:

  • simulate 只执行一次电路,这种方法如果只是从结果状态中取样速度是非常快的,但是如果有中间测量,则最终结果取决于这些测量的结果。
  • run 则会为每一个重复请求执行一次电路,因此采样速度要慢得多,但是中间测量值会在每次重复中重新采样。如果没有中间测量值,则重新定向到更快的执行方式 .run simulate

如果存在中间测量值,则警告将消失:

代码语言:javascript复制
# Define a circuit with intermediate measurements.
q0 = cirq.LineQubit(0)
circuit = cirq.Circuit(
    cirq.X(q0)**0.5, cirq.measure(q0, key='m0'),
    cirq.X(q0)**0.5, cirq.measure(q0, key='m1'),
    cirq.X(q0)**0.5, cirq.measure(q0, key='m2'),
)
print("Circuit:")
print(circuit)
print()

# Simulate the circuit with qsim and return just the measurement values.
print('qsim results:')
qsim_simulator = qsimcirq.QSimSimulator()
qsim_results = qsim_simulator.run(circuit, repetitions=5)
print(qsim_results)

输出结果:

代码语言:javascript复制
Circuit:
0: ───X^0.5───M('m0')───X^0.5───M('m1')───X^0.5───M('m2')───

qsim results:
m0=00100
m1=00011
m2=00010

振幅评估

qsim 还可以计算特定输出比特字符串的幅度

代码语言:javascript复制
# Define a simple circuit.
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(cirq.H(q0), cirq.CX(q0, q1))
print("Circuit:")
print(circuit)
print()

# Simulate the circuit with qsim and return the amplitudes for |00) and |01).
print('Cirq results:')
cirq_simulator = cirq.Simulator()
cirq_results = cirq_simulator.compute_amplitudes(
    circuit, bitstrings=[0b00, 0b01])
print(cirq_results)
print()

# Simulate the circuit with qsim and return the amplitudes for |00) and |01).
print('qsim results:')
qsim_simulator = qsimcirq.QSimSimulator()
qsim_results = qsim_simulator.compute_amplitudes(
    circuit, bitstrings=[0b00, 0b01])
print(qsim_results)

输出结果为:

代码语言:javascript复制
Circuit:
0: ───H───@───
          │
1: ───────X───

Cirq results:
[0.70710677 0.j 0.         0.j]

qsim results:
[(0.7071067690849304 0j), 0j]

性能基准

下面的代码示例在 4×5 量子位网格上生成一个深度 16 的电路,然后针对基本的 Cirq 模拟器运行它。对于这种规模的电路,运行时的差异可能更大。

代码语言:javascript复制
import time

# Get a rectangular grid of qubits.
qubits = cirq.GridQubit.rect(4, 5)

# Generates a random circuit on the provided qubits.
circuit = cirq.experiments.random_rotations_between_grid_interaction_layers_circuit(
    qubits=qubits, depth=16)

# Simulate the circuit with Cirq and print the runtime.
cirq_simulator = cirq.Simulator()
cirq_start = time.time()
cirq_results = cirq_simulator.simulate(circuit)
cirq_elapsed = time.time() - cirq_start
print(f'Cirq runtime: {cirq_elapsed} seconds.')
print()

# Simulate the circuit with qsim and print the runtime.
qsim_simulator = qsimcirq.QSimSimulator()
qsim_start = time.time()
qsim_results = qsim_simulator.simulate(circuit)
qsim_elapsed = time.time() - qsim_start
print(f'qsim runtime: {qsim_elapsed} seconds.')
代码语言:javascript复制
Cirq runtime: 2.774596691131592 seconds.

qsim runtime: 0.10769104957580566 seconds.

qsim 性能可以通过将选项传递给模拟器构造函数来进一步调整,这些选项使用与 qsim_base 二进制文件相同的格式。下面的示例演示了如何在 qsim 中启用多线程来获得最佳性能(注意:需使用与计算机内核数或虚拟内核数相同的线程数)。

代码语言:javascript复制
# Use eight threads to parallelize simulation.
options = {'t': 8}

qsim_simulator = qsimcirq.QSimSimulator(options)
qsim_start = time.time()
qsim_results = qsim_simulator.simulate(circuit)
qsim_elapsed = time.time() - qsim_start
print(f'qsim runtime: {qsim_elapsed} seconds.')

输出的测量结果为:

代码语言:javascript复制
qsim runtime: 0.028814077377319336 seconds.

另一种选择是调整融合门的最大量子比特数。增加这个数值会增加计算强度,会在合适的环境设置下提高性能。

代码语言:javascript复制
# Increase maximum fused gate size to three qubits.
options = {'f': 3}

qsim_simulator = qsimcirq.QSimSimulator(options)
qsim_start = time.time()
qsim_results = qsim_simulator.simulate(circuit)
qsim_elapsed = time.time() - qsim_start
print(f'qsim runtime: {qsim_elapsed} seconds.')

结果为:

代码语言:javascript复制
qsim runtime: 0.10588359832763672 seconds.

参考链接

  1. Simulations of Quantum Circuits with Approximate Noise using qsim and Cirq (arxiv.org)
  2. Quantum Simulator | Google Quantum AI
  3. quantumlib/Cirq: A python framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits. (github.com)
  4. Cirq Turns 1.0 | Google Open Source Blog (googleblog.com)
  5. Cirq - Wikipedia

0 人点赞