Spanish
Idiomas
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

Nota

[1]:

import numpy as np
from qiskit import *


## Compuertas opacas¶

[2]:

from qiskit.circuit import Gate

my_gate = Gate(name='my_gate', num_qubits=2, params=[])

[3]:

qr = QuantumRegister(3, 'q')
circ = QuantumCircuit(qr)
circ.append(my_gate, [qr[0], qr[1]])
circ.append(my_gate, [qr[1], qr[2]])

circ.draw()

[3]:

     ┌──────────┐
q_0: ┤0         ├────────────
│  my_gate │┌──────────┐
q_1: ┤1         ├┤0         ├
└──────────┘│  my_gate │
q_2: ────────────┤1         ├
└──────────┘

## Compuertas compuestas¶

[5]:

# Build a sub-circuit
sub_q = QuantumRegister(2)
sub_circ = QuantumCircuit(sub_q, name='sub_circ')
sub_circ.h(sub_q[0])
sub_circ.crz(1, sub_q[0], sub_q[1])
sub_circ.barrier()
sub_circ.id(sub_q[1])
sub_circ.u(1, 2, -2, sub_q[0])

# Convert to a gate and stick it into an arbitrary place in the bigger circuit
sub_inst = sub_circ.to_instruction()

qr = QuantumRegister(3, 'q')
circ = QuantumCircuit(qr)
circ.h(qr[0])
circ.cx(qr[0], qr[1])
circ.cx(qr[1], qr[2])
circ.append(sub_inst, [qr[1], qr[2]])

circ.draw()

[5]:

     ┌───┐
q_0: ┤ H ├──■────────────────────
└───┘┌─┴─┐     ┌───────────┐
q_1: ─────┤ X ├──■──┤0          ├
└───┘┌─┴─┐│  sub_circ │
q_2: ──────────┤ X ├┤1          ├
└───┘└───────────┘

Los circuitos no se descomponen inmediatamente después de la conversión to_instruction para permitir el diseño del circuito en niveles de abstracción más altos. Cuando se desee, o antes de la compliación, los sub-circuitos se descomprondrán utilizando el método decompose.

[6]:

decomposed_circ = circ.decompose() # Does not modify original circuit
decomposed_circ.draw()

[6]:

     ┌─────────┐
q_0: ┤ U2(0,π) ├──■─────────────────────────────────────
└─────────┘┌─┴─┐     ┌───┐          ░ ┌───────────┐
q_1: ───────────┤ X ├──■──┤ H ├────■─────░─┤ U(1,2,-2) ├
└───┘┌─┴─┐└───┘┌───┴───┐ ░ └───┬───┬───┘
q_2: ────────────────┤ X ├─────┤ Rz(1) ├─░─────┤ I ├────
└───┘     └───────┘ ░     └───┘    

[7]:

from qiskit.circuit import Parameter

theta = Parameter('θ')

n = 5

qc = QuantumCircuit(5, 1)

qc.h(0)
for i in range(n-1):
qc.cx(i, i+1)

qc.barrier()
qc.rz(theta, range(5))
qc.barrier()

for i in reversed(range(n-1)):
qc.cx(i, i+1)
qc.h(0)
qc.measure(0, 0)

qc.draw('mpl')

[7]:


Podemos revisar los parámetros del circuito

[8]:

print(qc.parameters)

ParameterView([Parameter(θ)])


### Vinculando parámetros a valores¶

Todos los parámetros del circuito deben estar vinculados antes de enviar el circuito a un backend. Esto se puede hacer de la siguiente manera: - El método bind_parameters acepta un mapeo de diccionario de Parameters a valores, y devuelve un nuevo circuito con cada parámetro reemplazado por su valor correspondiente. Se admite el enlace parcial, en cuyo caso el circuito devuelto será parametrizado por cualquier Parameter que no se haya asignado a un valor.

[9]:

import numpy as np

theta_range = np.linspace(0, 2 * np.pi, 128)

circuits = [qc.bind_parameters({theta: theta_val})
for theta_val in theta_range]

circuits[-1].draw()

[9]:

     ┌───┐                     ░ ┌────────┐ ░                     ┌───┐┌─┐
q_0: ┤ H ├──■──────────────────░─┤ Rz(2π) ├─░──────────────────■──┤ H ├┤M├
└───┘┌─┴─┐                ░ ├────────┤ ░                ┌─┴─┐└───┘└╥┘
q_1: ─────┤ X ├──■─────────────░─┤ Rz(2π) ├─░─────────────■──┤ X ├──────╫─
└───┘┌─┴─┐           ░ ├────────┤ ░           ┌─┴─┐└───┘      ║
q_2: ──────────┤ X ├──■────────░─┤ Rz(2π) ├─░────────■──┤ X ├───────────╫─
└───┘┌─┴─┐      ░ ├────────┤ ░      ┌─┴─┐└───┘           ║
q_3: ───────────────┤ X ├──■───░─┤ Rz(2π) ├─░───■──┤ X ├────────────────╫─
└───┘┌─┴─┐ ░ ├────────┤ ░ ┌─┴─┐└───┘                ║
q_4: ────────────────────┤ X ├─░─┤ Rz(2π) ├─░─┤ X ├─────────────────────╫─
└───┘ ░ └────────┘ ░ └───┘                     ║
c: 1/═══════════════════════════════════════════════════════════════════╩═
0 
[12]:

backend = BasicAer.get_backend('qasm_simulator')
job = backend.run(transpile(circuits, backend))
counts = job.result().get_counts()


En el circuito de ejemplo, aplicamos una rotación global de $$R_z(\theta)$$ en un estado entrelazado de cinco qubits, y, por lo tanto, esperamos ver la oscilación en el qubit 0 a $$5\theta$$.

[13]:

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))

ax.plot(theta_range, list(map(lambda c: c.get('0', 0), counts)), '.-', label='0')
ax.plot(theta_range, list(map(lambda c: c.get('1', 0), counts)), '.-', label='1')

ax.set_xticks([i * np.pi / 2 for i in range(5)])
ax.set_xticklabels(['0', r'$\frac{\pi}{2}$', r'$\pi$', r'$\frac{3\pi}{2}$', r'$2\pi$'], fontsize=14)
ax.set_xlabel('θ', fontsize=14)
ax.set_ylabel('Counts', fontsize=14)
ax.legend(fontsize=14)

[13]:

<matplotlib.legend.Legend at 0x7f8fcb307710>


### Reduciendo el costo de compilación¶

La compilación sobre un circuito parametrizado antes de la vinculación puede, en algunos casos, reducir significativamente el tiempo de compilación en comparación con la compilación sobre un conjunto de circuitos enlazados.

[14]:

import time
from itertools import combinations
from qiskit.compiler import assemble
from qiskit.test.mock import FakeVigo

start = time.time()
qcs = []

theta_range = np.linspace(0, 2*np.pi, 32)

for n in theta_range:
qc = QuantumCircuit(5)

for k in range(8):
for i,j in combinations(range(5), 2):
qc.cx(i,j)
qc.rz(n, range(5))
for i,j in combinations(range(5), 2):
qc.cx(i,j)

qcs.append(qc)

compiled_circuits = transpile(qcs, backend=FakeVigo())
qobj = assemble(compiled_circuits, backend=FakeVigo())

end = time.time()
print('Time compiling over set of bound circuits: ', end-start)

Time compiling over set of bound circuits:  2.4267938137054443

[16]:

start = time.time()
qc = QuantumCircuit(5)
theta = Parameter('theta')

for k in range(8):
for i,j in combinations(range(5), 2):
qc.cx(i,j)
qc.rz(theta, range(5))
for i,j in combinations(range(5), 2):
qc.cx(i,j)

transpiled_qc = transpile(qc, backend=FakeVigo())
qobj = assemble([transpiled_qc.bind_parameters({theta: n})
for n in theta_range], backend=FakeVigo())
end = time.time()
print('Time compiling over parameterized circuit, then binding: ', end-start)

Time compiling over parameterized circuit, then binding:  1.4472951889038086


### Composición¶

Los circuitos parametrizados pueden estar compuestos como QuantumCircuits estándar. Generalmente, al componer dos circuitos parametrizados, el circuito resultante será parametrizado por la unión de los parámetros de los circuitos de entrada.

Sin embargo, los nombres de parámetros deben ser únicos dentro de un circuito determinado. Cuando se intenta añadir un parámetro cuyo nombre ya está presente en el circuito de destino: - si el origen y el destino comparten la misma instancia de Parameter, se supondrá que los parámetros son iguales y combinados - si el origen y el destino tienen instancias de Parameter diferentes, se generará un error

[17]:

phi = Parameter('phi')

sub_circ1 = QuantumCircuit(2, name='sc_1')
sub_circ1.rz(phi, 0)
sub_circ1.rx(phi, 1)

sub_circ2 = QuantumCircuit(2, name='sc_2')
sub_circ2.rx(phi, 0)
sub_circ2.rz(phi, 1)

qc = QuantumCircuit(4)
qr = qc.qregs[0]

qc.append(sub_circ1.to_instruction(), [qr[0], qr[1]])
qc.append(sub_circ2.to_instruction(), [qr[0], qr[1]])

qc.append(sub_circ2.to_instruction(), [qr[2], qr[3]])

print(qc.draw())

# The following raises an error: "QiskitError: 'Name conflict on adding parameter: phi'"
# phi2 = Parameter('phi')
# qc.u3(0.1, phi2, 0.3, 0)

     ┌────────────┐┌────────────┐
q_0: ┤0           ├┤0           ├
│  sc_1(phi) ││  sc_2(phi) │
q_1: ┤1           ├┤1           ├
├────────────┤└────────────┘
q_2: ┤0           ├──────────────
│  sc_2(phi) │
q_3: ┤1           ├──────────────
└────────────┘


Para insertar un subcircuito bajo una parametrización diferente, el método to_instruction acepta un argumento opcional (parameter_map) que, cuando está presente, generará instrucciones con el parámetro de origen sustituido por un nuevo parámetro.

[18]:

p = Parameter('p')
qc = QuantumCircuit(3, name='oracle')
qc.rz(p, 0)
qc.cx(0, 1)
qc.rz(p, 1)
qc.cx(1, 2)
qc.rz(p, 2)

theta = Parameter('theta')
phi = Parameter('phi')
gamma = Parameter('gamma')

qr = QuantumRegister(9)
larger_qc = QuantumCircuit(qr)
larger_qc.append(qc.to_instruction({p: theta}), qr[0:3])
larger_qc.append(qc.to_instruction({p: phi}), qr[3:6])
larger_qc.append(qc.to_instruction({p: gamma}), qr[6:9])
print(larger_qc.draw())

print(larger_qc.decompose().draw())

       ┌────────────────┐
q24_0: ┤0               ├
│                │
q24_1: ┤1 oracle(theta) ├
│                │
q24_2: ┤2               ├
└┬──────────────┬┘
q24_3: ─┤0             ├─
│              │
q24_4: ─┤1 oracle(phi) ├─
│              │
q24_5: ─┤2             ├─
┌┴──────────────┴┐
q24_6: ┤0               ├
│                │
q24_7: ┤1 oracle(gamma) ├
│                │
q24_8: ┤2               ├
└────────────────┘
┌───────────┐
q24_0: ┤ Rz(theta) ├──■─────────────────────────────────
└───────────┘┌─┴─┐┌───────────┐
q24_1: ─────────────┤ X ├┤ Rz(theta) ├──■───────────────
└───┘└───────────┘┌─┴─┐┌───────────┐
q24_2: ───────────────────────────────┤ X ├┤ Rz(theta) ├
┌─────────┐                   └───┘└───────────┘
q24_3: ─┤ Rz(phi) ├───■─────────────────────────────────
└─────────┘ ┌─┴─┐ ┌─────────┐
q24_4: ─────────────┤ X ├─┤ Rz(phi) ├───■───────────────
└───┘ └─────────┘ ┌─┴─┐ ┌─────────┐
q24_5: ───────────────────────────────┤ X ├─┤ Rz(phi) ├─
┌───────────┐                  └───┘ └─────────┘
q24_6: ┤ Rz(gamma) ├──■─────────────────────────────────
└───────────┘┌─┴─┐┌───────────┐
q24_7: ─────────────┤ X ├┤ Rz(gamma) ├──■───────────────
└───┘└───────────┘┌─┴─┐┌───────────┐
q24_8: ───────────────────────────────┤ X ├┤ Rz(gamma) ├
└───┘└───────────┘

[19]:

import qiskit.tools.jupyter
%qiskit_version_table


### Version Information

Qiskit SoftwareVersion
qiskit-terra0.19.0.dev0+be0ed5f
qiskit-aer0.8.2
qiskit-ignis0.6.0
qiskit-ibmq-provider0.16.0.dev0+4e20edc
System information
Python3.7.7 (default, May 6 2020, 04:59:01) [Clang 4.0.1 (tags/RELEASE_401/final)]
OSDarwin
CPUs6
Memory (Gb)32.0
Sat Jul 31 01:02:16 2021 EDT

### This code is a part of Qiskit

[ ]: