cunqa.mappers
Contains map-like callables to distribute circuits among vQPUS.
Variational Quantum Algorithms [1] require numerous executions of parametric cirucits,
where in each step of the optimization process new parameters are assigned to them. This implies
that, after parameters are updated, a new circuit must be created, transpiled and then sent to
the quantum processor or simulator. For simplifying this process, we have
QJobMapper and QPUCircuitMapper classes. Both classes are conceived to
be used with Scipy optimizers [2] as the workers argument in global optimizers.
QJobMappertakes a list of existingQJobobjects, then, the class can be called passing a set of parameters and a cost function. This callable updates each existingQJobobject with such parameters through theupgrade_parametersmethod. Then, it gathers the results of the executions and returns the value of the cost function for each.QPUCircuitMapperis instanciated with a circuit and instructions for its execution, together with a list of theQPUobjects. The difference withQJobMapperis that here the methodexecuteis mapped to each QPU, passing it the circuit with the given parameters assigned so that for this case severalQJobobjects are created.
Examples utilizing both classes can be found in the Examples gallery. These examples focus on optimization of VQAs, using a global optimizer called Differential Evolution [3].
References:
- class QJobMapper(qjobs)
Class to map the method
upgrade_parametersto a set of jobs sent to virtual QPUs.The core of the class is on its
__call__method, to which parameters that the methodupgrade_parameterstakes are passed together with a cost function, so that a the value for this cost for each initialQJobis returned.An example is shown below, once we have a list of
QJobobjects as qjobs:>>> mapper = QJobMapper(qjobs) >>> >>> # defining the parameters set accordingly to the number of parameters >>> # of the circuit and the number of QJobs in the list. >>> new_parameters = [...] >>> >>> # defining the cost function passed to the result of each QJob >>> def cost_function(result): >>> counts = result.counts >>> ... >>> return cost_value >>> >>> cost_values = mapper(cost_function, new_parameters)
We intuitively see how convenient this class can be for optimization algorithms: one has a parametric circuit to which updated sets of parameters can be sent, getting back the value of the cost function. Examples applied to optimizations are shown at the Examples gallery.
- Parameters:
qjobs (list[QJob])
- __call__(func, population)
Callable method to map the function func to the results of assigning population to the given jobs. Regarding the population, each set of parameters will be assigned to each
QJobobject, so the list must have size (N,p), being N the lenght ofqjobsand p the number of parameters in the circuit. Mainly, this is thought for the function to take aResultobject and to return a value. For example, the function can evaluate the expected value of an observable from the output of the circuit.- Parameters:
func (callable) – function to be passed to the results of the jobs.
population (list[list[int | float] | np.array[int | float]]) – list of numpy vectors to
jobs. (be mapped to the)
- Returns:
List of outputs of the function applied to the results of each job for the given population.
- class QPUCircuitMapper(qpus, circuit, **run_parameters)
Class to map the method
executeto a list of QPUs.The class is initialized with a list of
QPUobjects associated to the virtual QPUs that the optimization will require, together with the circuit and the simulation instructions needed for its execution.Then, its
__call__method takes a set of parameters as population to assign to the circuit. Each assembled circuit is sent to each virtual QPU with the instructions provided on the instatiation of the mapper. The method returns the value for the provided function func for the result of each simulation.Its use is pretty similar to
QJobMapper, though creatingQJobobjects ahead is not needed.>>> qpus = get_QPUs(...) >>> >>> # Creating the mapper with the pre-defined parametric circuit and other simulation instructions. >>> mapper = QPUCircuitMapper(qpus, circuit, shots = 1000, ...) >>> >>> # Defining the parameters set according to the number of parameters >>> # of the circuit and the number of QJobs in the list. >>> new_parameters = [...] >>> >>> # Defining the cost function passed to the result of each QJob >>> def cost_function(result): >>> counts = result.counts >>> ... >>> return cost_value >>> >>> cost_values = mapper(cost_function, new_parameters)
For each call of the mapper, circuits are assembled, jobs are sent, results are gathered and cost values are calculated. Its implementation for optimization problems is shown at the Examples gallery.
- Parameters:
qpus (list[QPU])
circuit (QuantumCircuit)
run_parameters (Any | None)
- circuit
Circuit to which parameters are assigned at the
QPUCircuitMapper.__call__method.- Type:
QuantumCircuit
- run_parameters
Any other run instructions needed for the simulation.
- Type:
Optional[Any]
- __call__(func, population)
Callable method to map the function func to the results of the circuits sent to the given QPUs after assigning them population. Regarding the population, each set of parameters will be assigned to each circuit, so the list must have size (N,p), being N the lenght of
qpusand p the number of parameters in the circuit. Mainly, this is thought for the function to take aResultobject and to return a value. For example, the function can evaluate the expected value of an observable from the output of the circuit.- Parameters:
func (func) – function to be mapped to the QPUs. It must take as argument a
Resultinstance.params (list[list[float | int]]) – population of vectors to be mapped to the circuits sent to the QPUs.
- Returns:
List of the results of the function applied to the output of the circuits sent to the QPUs.