Edit/summary
Everything below this first paragraph is my original question posted several days ago and involves a lot of speculating on a problem I knew less about at the time. The purpose of this first paragraph is mainly to rephrase my question more concisely in light of what I have learned since then. In summary, I had this issue where most code would run fine, except certain code in Qiskit seemed to run unreasonably slowly on the M1 architecture. I was not sure if this was due to Qiskit or one of its dependencies. I was able to track down that it is fermion to qubit operator mapping functions (and anything that utilizes them in any way, such as the UCCSD ansatz variation form) that run slowly. Everything else that I have checked seems to run fine. When I track the performance of lines of code involving these functions with time.perf_counter() and time.process_time(), the perf_counter time will be several times that of process_time, indicating to me that for some reason, the total program run time is much longer than the actual CPU processing time for these specific functions. For Intel-based machines, these two time measures are roughly the same, with perf_counter usually being a fraction of a second more. For code run on the M1 for which there are no run time issues, these two time measures are also roughly the same. Why this happens is a mystery to me and I would be interested in finding out why this happens, if this issue occurs for other functions, and if we can expect this to improve with future versions of Qiskit and other Python open source packages where this problem might also occur. The thing I plan to do next is to see if such fermion to Qubit operator mapping problems happen for other open source quantum computing packages such as OpenFermion as well.
Original Question:
Recently I upgraded my laptop and got a MacBook Pro with the M1 chip and have been playing around with Qiskit and other python code to make sure that everything runs fine so that I can make an informed decision as to whether or not I should return it. The first thing I did with this machine was to install the latest version of Anaconda, PySCF, and Qiskit. I have been going through the tutorials on the Qiskit documentation site. Everything has been working fine, until I tried to run the noiseless part of the code provided at:
https://qiskit.org/documentation/tutorials/algorithms/03_vqe_simulation_with_noise.html
If I run this code on the Jupiter notebooks provided by Anaconda, it takes about 10 minutes to finish and activity monitor indicates it uses about 30% of the CPU load on my computer. If I run the same code on the Jupyter notebooks provided by the IBM Quantum Experience Quantum Lab, it finishes in less than a minute and uses up no noticeable load on my CPU. The main bottleneck of this code seems to be on the line:
result = vqe.compute_minimum_eigenvalue(operator=H2_op)
If I change the backend from qasm_simulator to statevector_simulator, the code completes almost instantaneously. I have also tried running a code I wrote several months ago that calculates the dissociation curves of the first few energy levels of H2 using the QEOM algorithm provided by Qiskit. For both the qasm and statevector simulator backends, the code is painfully slow. For comparison, I ran it on my 2013 MacBook Pro and it was about 30 times faster than the 2020 M1.
I have my suspicions as to why this is, but I would like to find out exactly what the issue is. There appears to be no explicit compatibility issues. The python packages install fine and the code will run, but some code seems to run extremely slowly. My understanding is that Python 3.9.1rc1 is optimized for Apple silicon chips, but 3.9.0 and all other previous versions are not and have to use Rosetta 2:
https://www.python.org/downloads/release/python-391rc1/
The latest version of Anaconda seems to use python 3.8.5, probably because not all of the packages that it comes with are compatible with python 3.9.0 or 3.9.1rc1 yet. Is optimization the issue here or is it something else? If so, can we expected Anaconda to be updated to python 3.9.1rc1 in the near future? If this is the case, I can probably just be patient and wait it out since the IBM Quantum Experience Jupyter notebook servers seem to do the job just fine. (Maybe the code here is run on an external server and this is why, but I'm not sure.) Is the problem something with the backends in Qiskit or with one of the dependencies that variational algorithms in Qiskit use such as the Scipy optimizers? Are there any tests that I could run to find out exactly which packages are the problem? So far the only issues I have found involve variational algorithms on Qiskit, but I will keep searching.
Samples of code
Below are examples of code taken from the Qiskit tutorials where I seem to have this problem. Code involving Aer not involving chemistry classical and quantum eigenvalue problems seem to not have this problem.
from qiskit.chemistry.drivers import PySCFDriver, UnitsType, Molecule
from qiskit.chemistry.transformations import FermionicTransformation, FermionicQubitMappingType
from qiskit import BasicAer
from qiskit.aqua import QuantumInstance
from qiskit.chemistry.algorithms.ground_state_solvers.minimum_eigensolver_factories import VQEUCCSDFactory
from qiskit.chemistry.algorithms.ground_state_solvers import GroundStateEigensolver
import time
toc = time.perf_counter()
molecule = Molecule(geometry=[['H', [0., 0., 0.]],
['H', [0., 0., 0.735]]],
charge=0, multiplicity=1)
driver = PySCFDriver(molecule = molecule, unit=UnitsType.ANGSTROM, basis='sto3g')
transformation = FermionicTransformation(qubit_mapping=FermionicQubitMappingType.JORDAN_WIGNER)
vqe_solver = VQEUCCSDFactory(QuantumInstance(BasicAer.get_backend('statevector_simulator')))
calc = GroundStateEigensolver(transformation, vqe_solver)
toc = time.perf_counter()
res = calc.solve(driver)
tic = time.perf_counter()
print('program completed in {} seconds'.format(tic-toc))
from qiskit.chemistry.drivers import PySCFDriver, UnitsType, Molecule
from qiskit.chemistry.transformations import FermionicTransformation, FermionicQubitMappingType
from qiskit.aqua.algorithms import NumPyMinimumEigensolver
import time
molecule = Molecule(geometry=[['H', [0., 0., 0.]],
['H', [0., 0., 0.735]]],
charge=0, multiplicity=1)
driver = PySCFDriver(molecule = molecule, unit=UnitsType.ANGSTROM, basis='sto3g')
transformation = FermionicTransformation(qubit_mapping=FermionicQubitMappingType.JORDAN_WIGNER)
numpy_solver = NumPyMinimumEigensolver()
calc = GroundStateEigensolver(transformation, numpy_solver)
toc = time.perf_counter()
res = calc.solve(driver)
tic = time.perf_counter()
print('program complered in {} seconds'.format(tic-toc))
Tests
I have run this code on my M1 laptop, 2013 Intel-based laptop, and the IBM Jupyter servers and have used both time.perf_counter() and time.process_time() to track the performance of code on all three machines. On code where the M1 performs fine, these times are roughly the same on all three machines, but on code where the M1 appears to not perform well, perf_counter will be several times that of process_time on the M1. (e.g. CPU time roughly 0.7 seconds and total time 20 seconds for the first code given above) It appears that for certain code in Qiskit, the majority of the time taken to complete the code is spent on something other than CPU processing time and I do not know why. I don't have any other computational tasks going on in the background and CPU load is only about 3% or so when I'm not running code, so I do not think something like having lots of tabs open is responsible for this.