pauliengine 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pauliengine-0.1.2/.git_archival.txt +3 -0
- pauliengine-0.1.2/CMakeLists.txt +114 -0
- pauliengine-0.1.2/CMakeUserPresets.json +9 -0
- pauliengine-0.1.2/LICENSE +21 -0
- pauliengine-0.1.2/PKG-INFO +332 -0
- pauliengine-0.1.2/README.md +282 -0
- pauliengine-0.1.2/THIRD_PARTY_LICENSES.txt +15 -0
- pauliengine-0.1.2/cmake/compiler_flags/CXXFlags.cmake +79 -0
- pauliengine-0.1.2/cmake/compiler_flags/Clang.CXX.cmake +22 -0
- pauliengine-0.1.2/cmake/compiler_flags/GNU.CXX.cmake +9 -0
- pauliengine-0.1.2/cmake/compiler_flags/Intel.CXX.cmake +6 -0
- pauliengine-0.1.2/cmake/compiler_flags/MSVC.CXX.cmake +6 -0
- pauliengine-0.1.2/conan_profile +4 -0
- pauliengine-0.1.2/conanfile.txt +6 -0
- pauliengine-0.1.2/include/pauliengine/Info.h.in +29 -0
- pauliengine-0.1.2/include/pauliengine/PauliString.h +712 -0
- pauliengine-0.1.2/include/pauliengine/QubitHamiltonian.h +811 -0
- pauliengine-0.1.2/pyproject.toml +321 -0
- pauliengine-0.1.2/src/CMakeLists.txt +59 -0
- pauliengine-0.1.2/src/PauliString_test.cc +78 -0
- pauliengine-0.1.2/src/QubitHamiltonian.cpp +1 -0
- pauliengine-0.1.2/src/bindings/CMakeLists.txt +42 -0
- pauliengine-0.1.2/src/bindings/bindings.cpp +298 -0
- pauliengine-0.1.2/src/example.cpp +20 -0
- pauliengine-0.1.2/src/pauliengine/__init__.py +24 -0
- pauliengine-0.1.2/src/pauliengine/_version.py +24 -0
- pauliengine-0.1.2/src/pauliengine/pauli_string.py +96 -0
- pauliengine-0.1.2/src/pauliengine/qubit_hamiltonian.py +192 -0
- pauliengine-0.1.2/tests/test_package.py +9 -0
- pauliengine-0.1.2/tests/test_pauli_string.py +672 -0
- pauliengine-0.1.2/tests/test_qubit_hamiltonian.py +1101 -0
- pauliengine-0.1.2/tools/benchmarks/README.md +95 -0
- pauliengine-0.1.2/tools/benchmarks/__init__.py +1 -0
- pauliengine-0.1.2/tools/benchmarks/benchmark.py +167 -0
- pauliengine-0.1.2/tools/benchmarks/compare.py +208 -0
- pauliengine-0.1.2/tools/benchmarks/generate.py +77 -0
- pauliengine-0.1.2/tools/benchmarks/hardware.py +130 -0
- pauliengine-0.1.2/tools/benchmarks/plot.py +100 -0
- pauliengine-0.1.2/tools/benchmarks/results/.gitkeep +0 -0
- pauliengine-0.1.2/tools/benchmarks/run.py +136 -0
- pauliengine-0.1.2/tools/install-deps.sh +81 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.28...4.2.1)
|
|
2
|
+
|
|
3
|
+
if(SKBUILD)
|
|
4
|
+
# this value doesn't really matter, as it will be set by scikit-build-core
|
|
5
|
+
set(PROJECT_VERSION "0.1.0")
|
|
6
|
+
else()
|
|
7
|
+
include(FetchContent)
|
|
8
|
+
FetchContent_Declare(
|
|
9
|
+
CMakeExtraUtils
|
|
10
|
+
QUIET
|
|
11
|
+
URL
|
|
12
|
+
https://github.com/LecrisUT/CMakeExtraUtils/archive/refs/tags/v0.4.1.tar.gz
|
|
13
|
+
SOURCE_DIR
|
|
14
|
+
${CMAKE_CURRENT_BINARY_DIR}/external/upstream/_srcs/CMakeExtraUtils
|
|
15
|
+
)
|
|
16
|
+
FetchContent_MakeAvailable(CMakeExtraUtils)
|
|
17
|
+
|
|
18
|
+
include(DynamicVersion)
|
|
19
|
+
dynamic_version(PROJECT_PREFIX pauliengine_)
|
|
20
|
+
endif()
|
|
21
|
+
|
|
22
|
+
project(pauliengine LANGUAGES CXX VERSION ${PROJECT_VERSION})
|
|
23
|
+
|
|
24
|
+
# if CMAKE_BUILD_TYPE undefined, we set it to Release
|
|
25
|
+
if(NOT CMAKE_BUILD_TYPE)
|
|
26
|
+
set(CMAKE_BUILD_TYPE "Release")
|
|
27
|
+
endif()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Options handling utilities Macro for printing an option in a consistent manner
|
|
31
|
+
# Written by Lori A. Burns (@loriab) and Ryan M. Richard (@ryanmrichard) Syntax:
|
|
32
|
+
# print_option(<option to print> <was specified>)
|
|
33
|
+
macro(print_option variable default)
|
|
34
|
+
if(NOT DEFINED ${variable} OR "${${variable}}" STREQUAL "")
|
|
35
|
+
message(STATUS "Setting (unspecified) option ${variable}: ${default}")
|
|
36
|
+
else()
|
|
37
|
+
message(STATUS "Setting option ${variable}: ${${variable}}")
|
|
38
|
+
endif()
|
|
39
|
+
endmacro()
|
|
40
|
+
|
|
41
|
+
# Wraps an option with default ON/OFF. Adds nice messaging to option() Written
|
|
42
|
+
# by Lori A. Burns (@loriab) and Ryan M. Richard (@ryanmrichard) Syntax:
|
|
43
|
+
# option_with_print(<option name> <description> <default value>)
|
|
44
|
+
macro(option_with_print variable msge default)
|
|
45
|
+
print_option(${variable} ${default})
|
|
46
|
+
option(${variable} ${msge} ${default})
|
|
47
|
+
endmacro()
|
|
48
|
+
|
|
49
|
+
# Wraps an option with a default other than ON/OFF and prints it Written by Lori
|
|
50
|
+
# A. Burns (@loriab) and Ryan M. Richard (@ryanmrichard) NOTE: Can't combine
|
|
51
|
+
# with above b/c CMake handles ON/OFF options specially NOTE2: CMake variables
|
|
52
|
+
# are always defined so need to further check for if they are the NULL string.
|
|
53
|
+
# This is also why we need the force Syntax: option_with_default(<option name>
|
|
54
|
+
# <description> <default value>)
|
|
55
|
+
macro(option_with_default variable msge default)
|
|
56
|
+
print_option(${variable} "${default}")
|
|
57
|
+
if(NOT DEFINED ${variable} OR "${${variable}}" STREQUAL "")
|
|
58
|
+
set(${variable} "${default}" CACHE STRING ${msge} FORCE)
|
|
59
|
+
endif()
|
|
60
|
+
endmacro()
|
|
61
|
+
|
|
62
|
+
set(CMAKE_CXX_STANDARD 20 CACHE STRING "C++ standard")
|
|
63
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "C++ standard required")
|
|
64
|
+
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "C++ extensions")
|
|
65
|
+
|
|
66
|
+
include(${PROJECT_SOURCE_DIR}/cmake/compiler_flags/CXXFlags.cmake)
|
|
67
|
+
|
|
68
|
+
message(STATUS "${PROJECT_NAME} version: ${PROJECT_VERSION_FULL}")
|
|
69
|
+
|
|
70
|
+
# report on compiler flags in use
|
|
71
|
+
message(STATUS "Configuring a ${CMAKE_BUILD_TYPE} build")
|
|
72
|
+
string(TOUPPER ${CMAKE_BUILD_TYPE} _cmake_build_type_upper)
|
|
73
|
+
|
|
74
|
+
message(STATUS "Compiler flags for ${CMAKE_CXX_COMPILER_ID}")
|
|
75
|
+
message(STATUS " From environment : ${CMAKE_CXX_FLAGS}")
|
|
76
|
+
set(
|
|
77
|
+
_cmake_build_type_specific_flags
|
|
78
|
+
"${CMAKE_CXX_FLAGS_${_cmake_build_type_upper}}"
|
|
79
|
+
)
|
|
80
|
+
message(
|
|
81
|
+
STATUS
|
|
82
|
+
" Build-type-specific : ${_cmake_build_type_specific_flags}"
|
|
83
|
+
)
|
|
84
|
+
message(STATUS " Vectorization flag : ${ARCH_FLAG}")
|
|
85
|
+
message(
|
|
86
|
+
STATUS
|
|
87
|
+
" Project defaults : ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ${pauliengine_CXX_FLAGS}"
|
|
88
|
+
)
|
|
89
|
+
message(STATUS " User-appended : ${EXTRA_CXXFLAGS}")
|
|
90
|
+
|
|
91
|
+
include(GNUInstallDirs)
|
|
92
|
+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
|
|
93
|
+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
|
94
|
+
|
|
95
|
+
# OpenMP is optional — code falls back to sequential loops when unavailable.
|
|
96
|
+
# On macOS with AppleClang you may need to `brew install libomp` and set
|
|
97
|
+
# OpenMP_ROOT to the Homebrew prefix before configuring.
|
|
98
|
+
find_package(OpenMP)
|
|
99
|
+
if(OpenMP_CXX_FOUND)
|
|
100
|
+
message(STATUS "OpenMP: enabled (spec ${OpenMP_CXX_SPEC_DATE}, ${OpenMP_CXX_FLAGS})")
|
|
101
|
+
else()
|
|
102
|
+
message(STATUS "OpenMP: not found — building without parallel loops")
|
|
103
|
+
endif()
|
|
104
|
+
|
|
105
|
+
configure_file(
|
|
106
|
+
${PROJECT_SOURCE_DIR}/include/pauliengine/Info.h.in
|
|
107
|
+
${PROJECT_BINARY_DIR}/include/pauliengine/Info.h
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Conan Toolchain einbinden (nach: conan install .. --install-folder=build --build=missing)
|
|
111
|
+
include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake OPTIONAL RESULT_VARIABLE _found)
|
|
112
|
+
|
|
113
|
+
add_subdirectory(src)
|
|
114
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Leon Müller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: pauliengine
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Fast arithmetics for quantum operators (Pauli strings & Hamiltonians).
|
|
5
|
+
Keywords: quantum,quantum-computing,pauli,hamiltonian,symbolic,physics
|
|
6
|
+
Author-Email: Leon Müller <mueller.leon.home@gmail.com>, Jakob Kottmann <jakob.kottmann@gmail.com>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 Leon Müller
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Classifier: Development Status :: 4 - Beta
|
|
30
|
+
Classifier: Intended Audience :: Science/Research
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Programming Language :: Python
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering
|
|
43
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
44
|
+
Classifier: Typing :: Typed
|
|
45
|
+
Project-URL: Homepage, https://github.com/tequilahub/pauliengine
|
|
46
|
+
Project-URL: Repository, https://github.com/tequilahub/pauliengine
|
|
47
|
+
Project-URL: Issues, https://github.com/tequilahub/pauliengine/issues
|
|
48
|
+
Requires-Python: <3.14,>=3.10
|
|
49
|
+
Description-Content-Type: text/markdown
|
|
50
|
+
|
|
51
|
+
# PauliEngine — Fast Arithmetic for Quantum Operators
|
|
52
|
+
|
|
53
|
+
A C++ core with a nanobind Python frontend for working with Pauli strings and
|
|
54
|
+
qubit Hamiltonians. Coefficients can be numeric (`std::complex<double>`) or
|
|
55
|
+
fully symbolic (SymEngine).
|
|
56
|
+
|
|
57
|
+
See [arXiv:2601.02233](https://arxiv.org/abs/2601.02233) for the algorithmic
|
|
58
|
+
background.
|
|
59
|
+
|
|
60
|
+
> **Status.** Functional core with a large test suite. The Python
|
|
61
|
+
> API surface is stable. Sphinx docs are not published yet.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Highlights
|
|
66
|
+
|
|
67
|
+
- **Binary symplectic representation** — multiplication, commutators, and
|
|
68
|
+
hashing are O(n / 64) over the qubit count.
|
|
69
|
+
- **Two coefficient backends** — numeric (`complex<double>`) and symbolic
|
|
70
|
+
(`SymEngine::Expression`); cross-type arithmetic is handled automatically and
|
|
71
|
+
type-promotes the way you expect (any symbolic term → the whole Hamiltonian
|
|
72
|
+
becomes symbolic).
|
|
73
|
+
- **Compaction invariant** — every operation that returns a `QubitHamiltonian`
|
|
74
|
+
merges duplicate-operator terms and drops zero-coefficient terms. You never
|
|
75
|
+
need to call `simplify()` for correctness.
|
|
76
|
+
- **Tequila-compatible API** — `qubits`, `n_qubits`, `is_hermitian`,
|
|
77
|
+
`is_antihermitian`, `dagger`, `conjugate`, `transpose`, `simplify(threshold)`,
|
|
78
|
+
`split`, `map_qubits`, `power` / `__pow__`, `to_matrix`, `paulistrings`,
|
|
79
|
+
`count_measurements`, `is_all_z`.
|
|
80
|
+
- **OpenFermion bridge** — the `QubitHamiltonian` factory accepts an
|
|
81
|
+
`openfermion.QubitOperator` directly; `to_openfermion` and `from_openfermion`
|
|
82
|
+
helpers are available.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Quickstart
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import pauliengine as pe
|
|
90
|
+
|
|
91
|
+
# A single Pauli string: dict-of-operators style.
|
|
92
|
+
p1 = pe.PauliString(1.0, {0: "Z", 1: "X"})
|
|
93
|
+
|
|
94
|
+
# Symbolic coefficient — anything coercible to a SymEngine Expression.
|
|
95
|
+
p2 = pe.PauliString("a", {1: "X"})
|
|
96
|
+
|
|
97
|
+
# OpenFermion-style: PauliString((coeff, [(Pauli, qubit), ...]))
|
|
98
|
+
p3 = pe.PauliString((1.0, [("X", 0), ("Y", 2)]))
|
|
99
|
+
|
|
100
|
+
# Build a Hamiltonian from a list of PauliStrings (or (coeff, dict) tuples).
|
|
101
|
+
H = pe.QubitHamiltonian([p1, p2, p3])
|
|
102
|
+
|
|
103
|
+
print(H.qubits()) # [0, 1, 2]
|
|
104
|
+
print(H.is_hermitian()) # True
|
|
105
|
+
print(H.dagger()) # for Hermitian H this is just H
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Tests are in `tests/`:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pytest tests/
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Construction
|
|
117
|
+
|
|
118
|
+
`pe.PauliString` accepts several input shapes:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
pe.PauliString(1.0, {0: "Z", 1: "X"}) # dict input
|
|
122
|
+
pe.PauliString(1.0, "X0 Y1 Z2") # space-separated string input
|
|
123
|
+
pe.PauliString((1.0, [("X", 0), ("Y", 2)])) # OpenFermion-style (coeff, list)
|
|
124
|
+
pe.PauliString("a", {0: "X"}) # symbolic coefficient
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`pe.QubitHamiltonian` accepts:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
pe.QubitHamiltonian([ps1, ps2, ...]) # list of PauliStrings
|
|
131
|
+
pe.QubitHamiltonian([(1.0, {0: "X"}), ("a", {1: "Z"})]) # list of tuples
|
|
132
|
+
pe.QubitHamiltonian(openfermion_qubit_operator) # see OpenFermion bridge
|
|
133
|
+
pe.QubitHamiltonian.zero() # empty Hamiltonian
|
|
134
|
+
pe.QubitHamiltonian.unit() # identity (single term, coeff 1, no ops)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
If any term in the list is symbolic, the resulting Hamiltonian is symbolic.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Arithmetic
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# PauliString * PauliString, with the right factors of i from Pauli algebra.
|
|
145
|
+
p4 = pe.PauliString(1.0, {0: "X"}) * pe.PauliString(1.0, {0: "Y"}) # -> 1j * Z(0)
|
|
146
|
+
|
|
147
|
+
# Scalar multiplication on both sides; +, -, unary -, and addition between
|
|
148
|
+
# PauliStrings (returns a QubitHamiltonian).
|
|
149
|
+
H1 = p1 + p2 - p3
|
|
150
|
+
H2 = 0.5 * H1 + (-H1) * 2j
|
|
151
|
+
H3 = H1 ** 3 # integer powers
|
|
152
|
+
c = H1.commutator(H2) # commutator (also available on PauliString)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Cross-type multiplication (numeric × symbolic) is supported and promotes the
|
|
156
|
+
result to symbolic.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Inspection and properties
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
H.size() # number of Pauli-string terms (also len(H))
|
|
164
|
+
H.qubits() # sorted list of qubits with non-identity operators
|
|
165
|
+
H.n_qubits() # len(H.qubits())
|
|
166
|
+
H.is_all_z()
|
|
167
|
+
H.is_hermitian() # True iff every coefficient is real
|
|
168
|
+
H.is_antihermitian() # True iff every coefficient is purely imaginary
|
|
169
|
+
H.count_measurements() # 1 if all-Z, else len(H)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
For a single `PauliString`:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
ps.size() # number of non-identity Pauli ops (also len(ps))
|
|
176
|
+
ps.count_y() # number of Y operators (used by conjugate/transpose)
|
|
177
|
+
ps.naked() # same operator with coefficient 1
|
|
178
|
+
ps.key_openfermion() # OpenFermion-style key
|
|
179
|
+
ps.get_pauli_at_index(q) # "I" / "X" / "Y" / "Z"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Transformations
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
H.dagger() # complex-conjugate each coefficient
|
|
188
|
+
H.conjugate() # complex conjugation (flips a sign per Y operator)
|
|
189
|
+
H.transpose() # transpose (flips a sign per Y operator, no conjugation)
|
|
190
|
+
H.simplify(1e-10) # drop terms with |coefficient| <= threshold
|
|
191
|
+
H.split() # -> (hermitian, anti_hermitian) pair (numeric coeffs only)
|
|
192
|
+
H.map_qubits({0: 5, 1: 2})
|
|
193
|
+
H.power(3) # also via H ** 3
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
> `split()` and `to_matrix()` require coefficients that evaluate to a complex
|
|
197
|
+
> number — call `H.subs({...})` first on symbolic Hamiltonians.
|
|
198
|
+
|
|
199
|
+
### Dense matrix
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
import numpy as np
|
|
203
|
+
|
|
204
|
+
M = np.array(H.to_matrix()) # 2**n x 2**n, ignores unused qubits
|
|
205
|
+
M_full = np.array(H.to_matrix(ignore_unused_qubits=False)) # absolute qubit indices
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
## Symbolic coefficients
|
|
212
|
+
|
|
213
|
+
Any string coefficient (or `SymEngine::Expression` from C++) makes the term
|
|
214
|
+
symbolic. Symbolic PauliStrings and Hamiltonians support every arithmetic
|
|
215
|
+
operation plus:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
H = pe.QubitHamiltonian([("a", {0: "X"}), ("b", {1: "Z"})])
|
|
219
|
+
|
|
220
|
+
dH = H.diff("a") # symbolic derivative
|
|
221
|
+
H2 = H.subs({"a": 2.0}) # substitute and evaluate
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`diff` is also available on `PauliString`. Mixing symbolic and numeric inputs
|
|
225
|
+
is fine: the factory scans every element and uses the symbolic builder if
|
|
226
|
+
needed.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## OpenFermion bridge
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from openfermion import QubitOperator
|
|
234
|
+
qop = 1.5 * QubitOperator("X0 Y1") + 0.5j * QubitOperator("Z2")
|
|
235
|
+
|
|
236
|
+
# Factory accepts QubitOperator directly:
|
|
237
|
+
H = pe.QubitHamiltonian(qop)
|
|
238
|
+
|
|
239
|
+
# Or use the explicit helpers:
|
|
240
|
+
H = pe.from_openfermion(qop)
|
|
241
|
+
qop_back = pe.QubitHamiltonian.to_openfermion(H)
|
|
242
|
+
assert qop == qop_back
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`openfermion` is an optional dependency — `from_openfermion` /
|
|
246
|
+
`to_openfermion` import it lazily and raise `ImportError` with a helpful
|
|
247
|
+
message if it is missing.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## C++ usage
|
|
252
|
+
|
|
253
|
+
The library is a header-only template under `include/pauliengine/`. Both
|
|
254
|
+
`PauliString<Coeff>` and `QubitHamiltonian<Coeff>` work for
|
|
255
|
+
`Coeff = std::complex<double>` and `Coeff = SymEngine::Expression`. Every
|
|
256
|
+
operation exposed in Python is available in C++ with the same name.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Installation
|
|
261
|
+
|
|
262
|
+
### From PyPI
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
pip install pauliengine
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Prebuilt wheels are available for Linux (x86_64/aarch64), macOS (arm64) and
|
|
269
|
+
Windows (x86_64/arm64) on Python 3.10–3.13. Installing from the source
|
|
270
|
+
distribution requires the build dependencies below.
|
|
271
|
+
|
|
272
|
+
### Build dependencies
|
|
273
|
+
|
|
274
|
+
- A C++20 compiler (MSVC 19.3+, GCC 11+, or Clang 14+)
|
|
275
|
+
- CMake 3.20+
|
|
276
|
+
- Python 3.10–3.13
|
|
277
|
+
- [Conan 2](https://conan.io) (to pull in SymEngine)
|
|
278
|
+
- [nanobind](https://github.com/wjakob/nanobind) (build-time)
|
|
279
|
+
|
|
280
|
+
### Install from source
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
pip install conan
|
|
284
|
+
conan profile detect
|
|
285
|
+
conan install . --output-folder=build --build=missing
|
|
286
|
+
pip install .
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The CMake build picks up the Conan toolchain from `build/conan_toolchain.cmake`.
|
|
290
|
+
For an editable / development install use `pip install -e .` instead of
|
|
291
|
+
`pip install .`.
|
|
292
|
+
|
|
293
|
+
### Windows notes
|
|
294
|
+
|
|
295
|
+
If you are on Windows and have not built SymEngine before, the Conan step will
|
|
296
|
+
build it from source on first install — that takes a few minutes. Subsequent
|
|
297
|
+
builds use the cached artifact.
|
|
298
|
+
|
|
299
|
+
> **Performance note.** PauliEngine can be built without SymEngine, but
|
|
300
|
+
> symbolic coefficients are unavailable in that mode and the runtime cost of
|
|
301
|
+
> certain numeric paths increases.
|
|
302
|
+
|
|
303
|
+
### macOS prerequisite
|
|
304
|
+
|
|
305
|
+
Conan does not currently ship a prebuilt SymEngine binary for macOS. Build it
|
|
306
|
+
from source once before the main install step:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
conan install --build=symengine/0.14.0
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Subsequent installs pick up the cached artifact, so this only needs to be done
|
|
313
|
+
the first time.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
## Testing
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
pip install pytest
|
|
323
|
+
pytest tests/
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Citation
|
|
330
|
+
|
|
331
|
+
If you use PauliEngine in academic work, please cite
|
|
332
|
+
[arXiv:2601.02233](https://arxiv.org/abs/2601.02233).
|