#!/usr/bin/env python # coding: utf-8 # # Parallel GST using MPI # The purpose of this tutorial is to demonstrate how to compute GST estimates in parallel (using multiple CPUs or "processors"). The core PyGSTi computational routines are written to take advantage of multiple processors via the MPI communication framework, and so one must have a version of MPI and the `mpi4py` python package installed in order use run pyGSTi calculations in parallel. # # Since `mpi4py` doesn't play nicely with Jupyter notebooks, this tutorial is a bit more clunky than the others. In it, we will create a standalone Python script that imports `mpi4py` and execute it. # # We will use as an example the same "standard" single-qubit model of the first tutorial. We'll first create a dataset, and then a script to be run in parallel which loads the data. The creation of a simulated data is performed in the same way as the first tutorial. Since *random* numbers are generated and used as simulated counts within the call to `generate_fake_data`, it is important that this is *not* done in a parallel environment, or different CPUs may get different data sets. (This isn't an issue in the typical situation when the data is obtained experimentally.) # In[1]: #Import pyGSTi and the "stardard 1-qubit quantities for a model with X(pi/2), Y(pi/2), and idle gates" import pygsti from pygsti.construction import std1Q_XYI #Create a data set target_model = std1Q_XYI.target_model() fiducials = std1Q_XYI.fiducials germs = std1Q_XYI.germs maxLengths = [1,2,4,8,16,32] mdl_datagen = target_model.depolarize(op_noise=0.1, spam_noise=0.001) listOfExperiments = pygsti.construction.make_lsgst_experiment_list(target_model.operations.keys(), fiducials, fiducials, germs, maxLengths) ds = pygsti.construction.generate_fake_data(mdl_datagen, listOfExperiments, nSamples=1000, sampleError="binomial", seed=1234) pygsti.io.write_dataset("example_files/mpi_example_dataset.txt", ds) # Next, we'll write a Python script that will load in the just-created `DataSet`, run GST on it, and write the output to a file. The only major difference between the contents of this script and previous examples is that the script imports `mpi4py` and passes a MPI comm object (`comm`) to the `do_long_sequence_gst` function. Since parallel computing is best used for computationaly intensive GST calculations, we also demonstrate how to set a per-processor memory limit to tell pyGSTi to partition its computations so as to not exceed this memory usage. Lastly, note the use of the `gaugeOptParams` argument of `do_long_sequence_gst`, which can be used to weight different model members differently during gauge optimization. # In[2]: mpiScript = """ import time import pygsti from pygsti.construction import std1Q_XYI #get MPI comm from mpi4py import MPI comm = MPI.COMM_WORLD print("Rank %d started" % comm.Get_rank()) #define target model, fiducials, and germs as before target_model = std1Q_XYI.target_model() fiducials = std1Q_XYI.fiducials germs = std1Q_XYI.germs maxLengths = [1,2,4,8,16,32] #tell gauge optimization to weight the operation matrix # elements 100x more heavily than the SPAM vector elements, and # to specifically weight the Gx gate twice as heavily as the other # gates. goParams = {'itemWeights':{'spam': 0.01, 'gates': 1.0, 'Gx': 2.0} } #Specify a per-core memory limit (useful for larger GST calculations) memLim = 2.1*(1024)**3 # 2.1 GB #Perform TP-constrained GST target_model.set_all_parameterizations("TP") #load the dataset ds = pygsti.io.load_dataset("example_files/mpi_example_dataset.txt") start = time.time() results = pygsti.do_long_sequence_gst(ds, target_model, fiducials, fiducials, germs, maxLengths,memLimit=memLim, gaugeOptParams=goParams, comm=comm, verbosity=2) end = time.time() print("Rank %d finished in %.1fs" % (comm.Get_rank(), end-start)) if comm.Get_rank() == 0: import pickle pickle.dump(results, open("example_files/mpi_example_results.pkl","wb")) """ with open("example_files/mpi_example_script.py","w") as f: f.write(mpiScript) # Next, we run the script with 3 processors using `mpiexec`. The `mpiexec` executable should have been installed with your MPI distribution -- if it doesn't exist, try replacing `mpiexec` with `mpirun`. # In[3]: get_ipython().system(' mpiexec -n 3 python3 "example_files/mpi_example_script.py"') # Notice in the above that output within `do_long_sequence_gst` is not duplicated (only the first processor outputs to stdout) so that the output looks identical to running on a single processor. Finally, we just need to read the pickled `Results` object from file and proceed with any post-processing analysis. In this case, we'll just create a report. # In[4]: import pickle results = pickle.load(open("example_files/mpi_example_results.pkl","rb")) pygsti.report.create_standard_report(results, "example_files/mpi_example_brief", title="MPI Example Report", verbosity=2, auto_open=True) # In[ ]: