Quantum Computing -- Unitary synthesis based on Cartan decomposition

This code implements the algorithm(s) found in:

Fixed Depth Hamiltonian Simulation via Cartan Decomposition Efekan Kökcü, Thomas Steckmann, J. K. Freericks, Eugene F. Dumitrescu, Alexander F. Kemper https://arxiv.org/abs/2104.00728

Abstract: Simulating spin systems on classical computers is challenging for large systems due to the significant memory requirements. This makes Hamiltonian simulation by quantum computers a promising option due to the direct representation of quantum states in terms of its qubits. Standard algorithms for time evolution on quantum computers require circuits whose depth grows with time. We present a new algorithm, based on Cartan decomposition of the Lie algebra generated by the Hamiltonian, that generates a circuit with time complexity O(1) for ordered and disordered models of n spins. We highlight our algorithm for special classes of models where an O(n^2)-gate circuit emerges. Compared to product formulas with significantly larger gate counts, our algorithm drastically improves simulation precision. Our algebraic technique sheds light on quantum algorithms and will reduce gate requirements for near term simulation.

Authors:

  • Efekan Kökcü
  • Thomas Steckmann

Documentation:

Please see the Documentation and the Example Notebooks for information on the functions included in the package.

Documetation generated by pdoc in the google style. A google style reference document is included. To recompile the documentation, first comment out __all__ in CQS\__init__.py, then run pdoc -d google -o .\docs\ .\CQS\ from the root folder (requires pdoc)

If there are issues with the import statements, make sure the package is installed through pip

General Notes:

PauliStrings are formatted as one of the following:

  • Text based: AKA ‘PauliString’ formats the Pauli String σx⊗σy⊗σz⊗σI⊗σI as XYZII
  • Tuple Bases: AKA (PauliString) formats σx⊗σy⊗σz⊗σI⊗σI as (1,2,3,0,0) where each 0,1,2,3 referes the the standard index of the Pauli matricies: I, X, Y, Z/.

    Usage:

    The functionality is based on three object classes:

  1. Hamiltonian: The Hamiltonian object is used to construct information about the model that you wish to simulate. There are predefined models that can be used for example implementation, the user can define a custom Hamiltonian and pass it to the object, the user can combine existing Hamiltonians to generate the desired Hamiltonian (ex. XY + transverse field), or the user can define their own input. This is designed to be relatively straightforward, and the other definitions can serve as examples
  2. Cartan: The Cartan object is used to define a cartan decomposition on the "Hamiltonian Algebra" generated by Hamiltonian object. The "Hamiltonian Algebra, g(H) or g, is defined as the set of Pauli Strings that can be generated through nested commutators on the Hamiltonian. Thus, g(H) is a closed Lie algebra. We can then perform a Cartan decomposition, which splits g into two components, k and m, based on some involution. The Cartan object has a list of predefined Cartan involutions, although users are encouraged to add an name their own implementations. Finally, the Hamiltonian algebra has as Cartan Subalgebra h, which is a maximal abelian subalgebra that is contained within the m partition. This is generated by the object. After generated the Cartan object, the involution (k and m) can be altered, and h can be regenerated based on a list of commuting terms in m. h is generally not unique.
  3. FindParameters: The FindParameters object optimizes the terms in the cartan decomposition to generate a time evolution circuit for the Hamiltonian. For details of the theory, please see the paper. The Find Parameters object relies on a cost function formulated by Earp and Pachos and improved in the original paper by Kokcu et. al. The Find Parameters object takes a filename, a Cartan object (which contains a Hamiltonian object), and allows for changes in the optimizer function (ex. BFGS gradient decent or Powell), or the optimization accuracy. Warning: Runtime scales quickly with system size.

For example, to use these objects to generate the decomposition for the time evolution of the four site 1D lattice XY model, the code would be as follows:

Installation:

To install the functions as a package, the easiest method is to run:


  git clone https://github.com/kemperlab/cartan-quantum-synthesizer.git
  
  cd ./cartan-quantum-synthesizer/
  
  pip install .

This will install the package. You can now import the key objects using

from CQS.methods import *

which is equivalent to

from CQS.methods import Hamiltonian, Cartan, FindParameters

Define the parameters of the model:

Define the number of lattice points

sites = 4

Define the model information.

model = [(1,'xy', False)]

This is an open boundary condition 1D lattice with the XY model. Formatted as [(Coefficient, 'ModelName'), closedBoundaryCondition)].

The Hamiltonian would be: 1*XXII + 1*YYII + 1*IXXI + 1*IYYI + 1*IIXX + 1*IIYY.

Create the Hamiltonian Object:

xy = Hamiltonian(sites,model)

Define the Cartan Object:

xyC = Cartan(xy)

The default Involution is Even-Odd, which counts the number of X and Y terms in each component of the algebra.

Run the FindParameters object:

xyP = FindParameters(xyC)

xyP.printResult()

Additional Options:

Hamiltonian:

The Hamiltonian objects accepts model names as:

  1. A List of Tuples formatted as: (coefficient, 'nameOfModel', periodicboundaryCondition) where the periodicBoundaryCondition is optional and defaults to False.
  2. A List containing Tuples formatted as in method 1, except containing a list of coefficients matching the length and indexing of the 'modelName' Hamiltonian. It is possible to run the method first using a dummy coefficient to determine the order for formatting

These rely on the existing hamiltonian methods, and can be called by defining name= when initializing the Hamiltonian object or when calling Hamiltonian.addModel()

Alternatively, and for more general use cases, users can add their own coefficient, tuple pairs. This can be passed to the method Hamiltonian.addTerms() as:

  1. A List of Tuples each containing (Coefficient, PauliString)Where the Pauli String is formatted as a Tuple
  2. A single Tuple formatted as above to add a single term
  3. A single tuple containing two Lists: One for the coefficients, one for the (PauliStrings) formatted as Tuples

For an example usage of the third input for .addTerms(), if the desired terms are formatted as a dictionary (and the Pauli Strings represented correctly in our Tuple format), the user can call:


testHamiltonian = Hamiltonian(4) 

hamiltonianDict = {(1,1,0,0): 3, 
                   (1,2,3,0): 2
                  }

testHamiltonian.addterms(([i for i in hamiltonianDict.values()], [i for i in hamiltonianDict.keys()])

Cartan:

The main methods that might be useful in Cartan are Cartan.decompose() and Cartan.subAlgebra(). decompose allows users to specify one of the Cartan Involutions by passing the name. The default option is EvenOdd, which might not be the best for all models. ‘CountY’ is generally very useful. subAlgebra allows users to pass a set of (pauliStrings), which must commute and exist in m, to be the basis for the Cartan Subalgebra. Generally, the subalgebra is not unique and clever choice of the subalgebra may reduce the circuit size.

Current State:

Version 0.2 - If you find an error in the code, please contact Thomas Steckmann (@tmsteck, tmsteckm at ncsu dot edu) or Efekan Kokcu

TODO:

  • Implement saving and loading