Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

removed mapomatic dependency #117

Merged
merged 5 commits into from
Aug 13, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
removed more deprecated backend calls, passed linting checks
nbronn committed Aug 9, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit cf35360880860859f3f4f84db485c07a184cadd1
18 changes: 9 additions & 9 deletions qiskit_research/utils/convenience.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import Gate
from qiskit.circuit.library import XGate
from qiskit.providers.backend import Backend
from qiskit.providers import Backend
from qiskit.transpiler import PassManager, Target
from qiskit.transpiler.passes.scheduling import ALAPScheduleAnalysis
from qiskit.transpiler.passes.scheduling.scheduling.base_scheduler import BaseScheduler
@@ -47,12 +47,12 @@ def add_dynamical_decoupling(
"""Add dynamical decoupling sequences and calibrations to circuits.

Adds dynamical decoupling sequences and the calibrations necessary
to run them on an IBM backend.
to run them on an IBM backend target.

Args:
circuits (Union[QuantumCircuit, List[QuantumCircuit], List[List[QuantumCircuit]]]):
input QuantumCircuit or sequences thereof.
backend (Backend): Backend to run on; gate timing is required for this method.
target (Target): Backend to run on; gate timing is required for this method.
dd_str (str): String describing DD sequence to use.
scheduler (BaseScheduler, optional): Scheduler, defaults to ALAPScheduleAnalysis.
add_pulse_cals (bool, optional): Add Pulse calibrations for non-basis
@@ -168,7 +168,7 @@ def add_pauli_twirls(
@overload
def scale_cr_pulses(
circuits: List[QuantumCircuit],
backend: Backend,
target: Target,
unroll_rzx_to_ecr: Optional[bool] = True,
force_zz_matches: Optional[bool] = True,
param_bind: Optional[dict] = None,
@@ -178,7 +178,7 @@ def scale_cr_pulses(
@overload
def scale_cr_pulses(
circuits: QuantumCircuit,
backend: Backend,
target: Target,
unroll_rzx_to_ecr: Optional[bool] = True,
force_zz_matches: Optional[bool] = True,
param_bind: Optional[dict] = None,
@@ -187,7 +187,7 @@ def scale_cr_pulses(

def scale_cr_pulses(
circuits,
backend,
target,
unroll_rzx_to_ecr: Optional[bool] = True,
force_zz_matches: Optional[bool] = True,
param_bind: Optional[dict] = None,
@@ -203,7 +203,7 @@ def scale_cr_pulses(
pass_manager = PassManager(
list(
cr_scaling_passes(
backend,
target,
templates,
unroll_rzx_to_ecr=unroll_rzx_to_ecr,
force_zz_matches=force_zz_matches,
@@ -216,15 +216,15 @@ def scale_cr_pulses(

def attach_cr_pulses(
circuits: Union[QuantumCircuit, List[QuantumCircuit]],
backend: Backend,
target: Target,
param_bind: dict,
) -> Union[QuantumCircuit, List[QuantumCircuit]]:
"""
Scale circuits using Pulse scaling technique from
http://arxiv.org/abs/2012.11660. Binds parameters
in param_bind and attaches pulse gates.
"""
pass_manager = PassManager(list(pulse_attaching_passes(backend, param_bind)))
pass_manager = PassManager(list(pulse_attaching_passes(target, param_bind)))
return pass_manager.run(circuits)


186 changes: 9 additions & 177 deletions qiskit_research/utils/cost_funcs.py
Original file line number Diff line number Diff line change
@@ -12,23 +12,26 @@

from __future__ import annotations

from typing import List, Tuple

from qiskit.circuit import QuantumCircuit
from qiskit.converters import circuit_to_dag
from qiskit.providers.backend import Backend
from qiskit.transpiler import Target
from qiskit.transpiler.passes.layout.vf2_utils import (
build_average_error_map,
build_interaction_graph,
score_layout,
)

from math import pi
import numpy as np


def avg_error_score(qc_isa: QuantumCircuit, target: Target) -> float:
"""Calculate average error score using vf2 utils

Args:
qc_isa (QuantumCircuit): transpiled circuit
target (Target): backend target

Returns:
float: average error score determined by average error map
"""
init_layout = qc_isa.layout.final_index_layout()
dag = circuit_to_dag(qc_isa)

@@ -40,174 +43,3 @@ def avg_error_score(qc_isa: QuantumCircuit, target: Target) -> float:
return score_layout(
avg_error_map, layout, im_graph_node_map, reverse_im_graph_node_map, im_graph
)


def cost_func_scaled_cr(
circ: QuantumCircuit,
layouts: List[List[int]],
backend: Backend,
) -> List[Tuple[List[int], float]]:
"""
A custom cost function that includes T1 and T2 computed during idle periods,
for an already transpiled and scheduled circuit circ

Parameters:
circ (QuantumCircuit): scheduled circuit of interest
backend (IBMQBackend): An IBM Quantum backend instance

Returns:
float: error
"""
out = []
props = backend.properties()
inst_sched_map = backend.defaults().instruction_schedule_map
dt = backend.configuration().dt
num_qubits = backend.configuration().num_qubits
t1s = [props.qubit_property(qq, "T1")[0] for qq in range(num_qubits)]
t2s = [props.qubit_property(qq, "T2")[0] for qq in range(num_qubits)]

error = 0.0
fid = 1.0
touched = set()
for layout in layouts:
for item in circ.data:
if item[0].num_qubits == 2:
q0 = circ.find_bit(item[1][0]).index
q1 = circ.find_bit(item[1][1]).index
if inst_sched_map.has("cx", qubits=[q0, q1]):
basis_2q_error = props.gate_error("cx", [q0, q1])
elif inst_sched_map.has("ecr", qubits=[q0, q1]):
basis_2q_error = props.gate_error("ecr", [q0, q1])
elif inst_sched_map.has("ecr", qubits=[q1, q0]):
basis_2q_error = props.gate_error("ecr", [q1, q0])
else:
print(
f"{backend.name} missing 2Q gate between qubit pair ({q0}, {q1})"
)

if item[0].name == "cx":
fid *= 1 - basis_2q_error
touched.add(q0)
touched.add(q1)

# if it is a scaled pulse derived from cx
elif item[0].name == "rzx":
cr_error = np.abs(float(item[0].params[0]) / (pi / 2)) * basis_2q_error

# assumes control qubit is actually control for cr
echo_error = props.gate_error("x", q0)

fid *= 1 - max(cr_error, 2 * echo_error)
elif item[0].name == "secr":
cr_error = (
np.abs((float(item[0].params[0])) / (pi / 2)) * basis_2q_error
)

# assumes control qubit is actually control for cr
echo_error = props.gate_error("x", q0)

fid *= 1 - max(cr_error, echo_error)

elif item[0].name in ["sx", "x"]:
q0 = circ.find_bit(item[1][0]).index
fid *= 1 - props.gate_error(item[0].name, q0)
touched.add(q0)

# if it is a dynamical decoupling pulse
elif item[0].name in ["xp", "xm", "y", "yp", "ym"]:
q0 = circ.find_bit(item[1][0]).index
fid *= 1 - props.gate_error("x", q0)
touched.add(q0)

elif item[0].name == "measure":
q0 = circ.find_bit(item[1][0]).index
fid *= 1 - props.readout_error(q0)
touched.add(q0)

elif item[0].name == "delay":
q0 = circ.find_bit(item[1][0]).index
# Ignore delays that occur before gates
# This assumes you are in ground state and errors
# do not occur.
if q0 in touched:
time = item[0].duration * dt
fid *= 1 - idle_error(time, t1s[q0], t2s[q0])

error = 1 - fid
out.append((layout, error))
return out


def idle_error(
time: float,
t1: float,
t2: float,
) -> float:
"""Compute the approx. idle error from T1 and T2
Parameters:
time (float): Delay time in sec
t1 (float): T1 time in sec
t2, (float): T2 time in sec
Returns:
float: Idle error
"""
t2 = min(t1, t2)
rate1 = 1 / t1
rate2 = 1 / t2
p_reset = 1 - np.exp(-time * rate1)
p_z = (1 - p_reset) * (1 - np.exp(-time * (rate2 - rate1))) / 2
return p_z + p_reset


def cost_func_ecr(
circ: QuantumCircuit,
layouts: List[List[int]],
backend: Backend,
) -> List[Tuple[List[int], float]]:
"""
A custom cost function that includes ECR gates in either direction

Parameters:
circ (QuantumCircuit): circuit of interest
layouts (list of lists): List of specified layouts
backend (IBMQBackend): An IBM Quantum backend instance

Returns:
list: Tuples of layout and cost
"""
out = []
inst_sched_map = backend.defaults().instruction_schedule_map
props = backend.properties()
for layout in layouts:
error = 0.0
fid = 1.0
touched = set()
for item in circ.data:
if item[0].name == "ecr":
q0 = layout[circ.find_bit(item[1][0]).index]
q1 = layout[circ.find_bit(item[1][1]).index]
if inst_sched_map.has("ecr", [q0, q1]):
fid *= 1 - props.gate_error("ecr", [q0, q1])
elif inst_sched_map.has("ecr", [q1, q0]):
fid *= 1 - props.gate_error("ecr", [q1, q0])
else:
print(
f"{backend.name} does not support {item[0].name} \
for qubit pair ({q0}, {q1})"
)
touched.add(q0)
touched.add(q1)

elif item[0].name in ["sx", "x"]:
q0 = layout[circ.find_bit(item[1][0]).index]
fid *= 1 - props.gate_error(item[0].name, q0)
touched.add(q0)

elif item[0].name == "measure":
q0 = layout[circ.find_bit(item[1][0]).index]
fid *= 1 - props.readout_error(q0)
touched.add(q0)

error = 1 - fid
out.append((layout, error))
return out
Loading