Repository URL to install this package:
|
Version:
0.12.2 ▾
|
# -*- coding: utf-8 -*-
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019, 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=no-name-in-module, import-error, invalid-name
"""
Controller for solving unitary evolution of a state-vector.
"""
import time
import numpy as np
from scipy.linalg.blas import get_blas_funcs
from qiskit.tools.parallel import parallel_map, CPU_COUNT
from .pulse_sim_options import PulseSimOptions
from .pulse_de_solver import setup_de_solver
from .pulse_utils import occ_probabilities, write_shots_memory
dznrm2 = get_blas_funcs("znrm2", dtype=np.float64)
def _full_simulation(exp, y0, pulse_sim_desc, pulse_de_model, solver_options=None):
"""
Set up full simulation, i.e. combining different (ideally modular) computational
resources into one function.
"""
solver_options = PulseSimOptions() if solver_options is None else solver_options
psi, ode_t = unitary_evolution(exp, y0, pulse_de_model, solver_options)
# ###############
# do measurement
# ###############
rng = np.random.RandomState(exp["seed"])
shots = pulse_sim_desc.shots
# Init memory
memory = np.zeros((shots, pulse_sim_desc.memory_slots), dtype=np.uint8)
qubits = []
memory_slots = []
tlist = exp["tlist"]
for acq in exp["acquire"]:
if acq[0] == tlist[-1]:
qubits += list(acq[1])
memory_slots += list(acq[2])
qubits = np.array(qubits, dtype="uint32")
memory_slots = np.array(memory_slots, dtype="uint32")
probs = occ_probabilities(qubits, psi, pulse_sim_desc.measurement_ops)
rand_vals = rng.rand(memory_slots.shape[0] * shots)
write_shots_memory(memory, memory_slots, probs, rand_vals)
return [memory, psi, ode_t]
def run_unitary_experiments(pulse_sim_desc, pulse_de_model, solver_options=None):
"""Runs unitary experiments for a given op_system
Parameters:
pulse_sim_desc (PulseSimDescription): description of pulse simulation
pulse_de_model (PulseInternalDEModel): description of de model
solver_options (PulseSimOptions): options
Returns:
tuple: two lists with experiment results
Raises:
Exception: if initial state is of incorrect format
"""
solver_options = PulseSimOptions() if solver_options is None else solver_options
if not pulse_sim_desc.initial_state.data.ndim != 1:
raise Exception("Initial state must be a state vector.")
y0 = pulse_sim_desc.initial_state.data.ravel()
# set num_cpus to the value given in settings if none in Options
if not solver_options.num_cpus:
solver_options.num_cpus = CPU_COUNT
# setup seeds array
seed = pulse_sim_desc.seed or np.random.randint(np.iinfo(np.int32).max - 1)
prng = np.random.RandomState(seed)
for exp in pulse_sim_desc.experiments:
exp["seed"] = prng.randint(np.iinfo(np.int32).max - 1)
map_kwargs = {"num_processes": solver_options.num_cpus}
# run simulation on each experiment in parallel
start = time.time()
exp_results = parallel_map(
_full_simulation,
pulse_sim_desc.experiments,
task_args=(
y0,
pulse_sim_desc,
pulse_de_model,
solver_options,
),
**map_kwargs,
)
end = time.time()
exp_times = (
np.ones(len(pulse_sim_desc.experiments)) * (end - start) / len(pulse_sim_desc.experiments)
)
return exp_results, exp_times
def unitary_evolution(exp, y0, pulse_de_model, solver_options=None):
"""
Calculates evolution when there is no noise, or any measurements that are not at the end
of the experiment.
Parameters:
exp (dict): dictionary containing experiment description
y0 (array): initial state
pulse_de_model (PulseInternalDEModel): container for de model
solver_options (PulseSimOptions): options
Returns:
array: results of experiment
Raises:
Exception: if ODE solving has errors
"""
solver_options = PulseSimOptions() if solver_options is None else solver_options
ODE = setup_de_solver(exp, y0, pulse_de_model, solver_options.de_options)
tlist = exp["tlist"]
for t in tlist[1:]:
ODE.integrate(t)
if ODE.successful():
psi = ODE.y / dznrm2(ODE.y)
else:
err_msg = "ODE method exited with status: %s" % ODE.return_code()
raise Exception(err_msg)
# apply final rotation to come out of rotating frame
psi_rot = np.exp(-1j * pulse_de_model.h_diag_elems * ODE.t)
psi *= psi_rot
return psi, ODE.t