Source code for quanguru.classes.modularSweep

"""
    Contain an implementation of the sweep that uses modular arithmetic.

    .. currentmodule:: quanguru.classes.modularSweep

    .. autosummary::

        runSimulation
        nonParalEvol
        paralEvol
        parallelTimeEvol
        _runSweepAndPrep
        timeDependent
        timeEvolDefault
        timeEvolBase

    .. |c| unicode:: U+2705
    .. |x| unicode:: U+274C
    .. |w| unicode:: U+2000

    =======================    ==================   ==============   ================   ===============
       **Function Name**        **Docstrings**       **Examples**     **Unit Tests**     **Tutorials**
    =======================    ==================   ==============   ================   ===============
      `runSimulation`            |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `nonParalEvol`             |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `paralEvol`                |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `parallelTimeEvol`         |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `_runSweepAndPrep`         |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `timeDependent`            |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `timeEvolDefault`          |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
      `timeEvolBase`             |w| |w| |w| |x|      |w| |w| |x|      |w| |w| |x|        |w| |w| |x|
    =======================    ==================   ==============   ================   ===============

"""

from functools import partial
from ..QuantumToolbox import densityMatrix, mat2Vec, vec2Mat

[docs]def runSimulation(qSim, p): # NOTE determine if more samples of a protocol step are requested. for protocol, _ in qSim.subSys.items(): if hasattr(protocol, 'steps'): if any((step.simulation.samples > 1 for step in protocol.steps.values())): protocol.stepSample = True if p is None: nonParalEvol(qSim) else: paralEvol(qSim, p)
# This is the single process function
[docs]def nonParalEvol(qSim): for ind in range(qSim.Sweep.indMultip): _runSweepAndPrep(qSim, ind) qSim.qRes._organiseSingleProcRes() # pylint: disable=protected-access qSim.qRes._finaliseAll(qSim.Sweep.inds) # pylint: disable=protected-access
# multi-processing functions
[docs]def paralEvol(qSim, p): results = p.map(partial(parallelTimeEvol, qSim), range(qSim.Sweep.indMultip), chunksize=1) qSim.qRes._organiseMultiProcRes(results, qSim.Sweep.inds) # pylint: disable=protected-access
# need this to avoid return part, which is only needed in multi-processing
[docs]def parallelTimeEvol(qSim, ind): _runSweepAndPrep(qSim, ind) return qSim.qRes._copyAllResBlank() # pylint: disable=protected-access
# These two functions, respectively, run Sweep and timeDependent (sweep) parameter updates # In the timeDependet case, evolFunc of first function is the second function
[docs]def _runSweepAndPrep(qSim, ind): if len(qSim.Sweep.inds) > 0: qSim.Sweep.runSweep(qSim.Sweep._indicesForSweep(ind, *qSim.Sweep.inds)) for protocol in qSim.subSys.keys(): if callable(qSim.evolFunc): protocol.currentState = protocol.initialState if not protocol._isOpen else densityMatrix(protocol.initialState)# pylint: disable=protected-access,line-too-long qSim.qRes._resetLast() # pylint: disable=protected-access qSim._computeBase__calculate("pre") for protocol in qSim.subSys.keys(): protocol._computeBase__calculate("pre") # pylint: disable=protected-access calledFor = [] for protocol, qsystem in qSim.subSys.items(): if qsystem not in calledFor: qsystem._computeBase__calculate("pre") # pylint: disable=protected-access calledFor.append(qsystem) timeDependent(qSim) qSim._computeBase__calculate("post") for protocol in qSim.subSys.keys(): protocol._computeBase__calculate("post") # pylint: disable=protected-access calledFor = [] for protocol, qsystem in qSim.subSys.items(): if qsystem not in calledFor: qsystem._computeBase__calculate("post") # pylint: disable=protected-access calledFor.append(qsystem)
[docs]def timeDependent(qSim): td = False if len(qSim.timeDependency.sweeps) > 0: td = True if list(qSim.timeDependency.sweeps.values())[0]._sweepList is not None: #pylint: disable=protected-access qSim.timeDependency.prepare() else: qSim.timeDependency._Sweep__inds = [qSim.stepCount] #pylint: disable=protected-access # TODO timeDependency sweep with multi-parameter is an undefined behaviour # if there are multiple sweeps when using sweeps for time-dependency, all of them has to run simultaneously. # if they are combinatorial multi-parameter sweep, the behavior is undefined. # labels: undefined behaviour qSim._timeBase__stepCount._value = qSim.timeDependency.indMultip # pylint: disable=protected-access for pro, sim in qSim.subSys.items(): # pylint: disable=protected-access sim.simulation._timeBase__stepCount._value = sim.simulation.timeDependency.indMultip # pylint: disable=protected-access pro.simulation._timeBase__stepCount._value = pro.simulation.timeDependency.indMultip # pylint: disable=protected-access timeEvolDefault(qSim, td)
# These are the specific solution method, user should define their own timeEvol function to use other solution methods # This flexibility should be reflected into protocol object
[docs]def timeEvolDefault(qSim, td): for protocol in qSim.subSys.keys(): protocol.sampleStates = [] if callable(qSim.evolFunc): qSim._Simulation__compute() # pylint: disable=protected-access for protocol in qSim.subSys.keys(): protocol._computeBase__compute(protocol.currentState) # pylint: disable=protected-access calledFor = [] for protocol, qsystem in qSim.subSys.items(): if qsystem not in calledFor: qsystem._computeBase__compute(protocol.currentState) # pylint: disable=protected-access calledFor.append(qsystem) if callable(qSim.evolFunc): for ind in range(qSim.stepCount): qSim._Simulation__index = ind # pylint: disable=protected-access if td: qSim.timeDependency.runSweep(qSim.timeDependency._indicesForSweep(ind, *qSim.timeDependency.inds)) qSim.evolFunc(qSim) qSim._Simulation__compute() # pylint: disable=protected-access for protocol in qSim.subSys.keys(): protocol._computeBase__compute(protocol.currentState) # pylint: disable=protected-access calledFor = [] for protocol, qsystem in qSim.subSys.items(): if qsystem not in calledFor: qsystem._computeBase__compute(protocol.currentState) # pylint: disable=protected-access calledFor.append(qsystem)
[docs]def timeEvolBase(qSim): for protocol in qSim.subSys.keys(): #pylint:disable=too-many-nested-blocks if protocol._isOpen: # pylint: disable=protected-access state = mat2Vec(protocol.currentState) state = protocol.unitary() @ state protocol.currentState = vec2Mat(state) else: protocol.sampleStates = [] if protocol.stepSample: for step in protocol.steps.values(): for _ in range(step.simulation.samples): protocol.currentState = step.unitary() @ protocol.currentState protocol.sampleStates.append(protocol.currentState) else: protocol.currentState = protocol.unitary() @ protocol.currentState
#protocol.sampleStates = [] #qSim.subSys[protocol]._computeBase__compute([protocol.currentState]) # pylint: disable=protected-access #sampleCompute = qSim is protocol.simulation # NOTE for time-dependent Hamiltonians in a digital quantum simulation, we may change the hamiltonian parameter # at evert dt, which might be divided into N steps. Below line was introduced for such cases. #for __ in range(int(protocol.simulation._timeBase__stepCount.value/qSim._timeBase__stepCount.value)): # pylint: disable=protected-access, line-too-long # noqa: E501 # NOTE in a protocol we may want to have more than 1 sample. Below line was introduced for such cases. #for ___ in range(protocol.simulation.samples): # NOTE this was using protocol.simulation compute function in above cases, if running simulation is not # protocol.simulation. protocol.compute is called by the running simulation. #if not sampleCompute: # protocol.simulation._Simulation__compute() # pylint: disable=protected-access # NOTE we may even want to have more samples during a specific step of a protocol. below lines cover that. this # was used quantum kicked top. it was appending the states into a list, which is passed to compute outside. #if protocol.stepSample: # for step in protocol.steps.values(): # for _ in range(step.simulation.samples): # protocol.currentState = step.unitary @ protocol.currentState # protocol.sampleStates.append(protocol.currentState) # NOTE below elif is when we just want samples from the protocol not steps, but we did not give compute. stores # the states to reach and use in some other compute #elif protocol.compute is None: # protocol.currentState = protocol.unitary @ protocol.currentState # protocol.sampleStates.append(protocol.currentState) # NOTE when only sample the protocol and compute is given, the states are passed 1 by 1. #else: #for step in protocol.subSys.values(): # protocol.currentState = step.unitary @ protocol.currentState # protocol._computeBase__compute([protocol.currentState]) # pylint: disable=protected-access