ShadowSim.py is an open-source Python library with two main purposes:
- Shadow Hamiltonian research: support analysis and further research on shadow Hamiltonian simulation.
- Algorithm comparison: make it easy to compare quantum simulation algorithms for open and closed systems.
Fork this repository to your own GitHub account, then clone your fork:
git clone https://github.com/<your-github-username>/ShadowSim.py.git
cd ShadowSim.pypython3 -m venv .venv
source .venv/bin/activatepip install --upgrade pip
pip install numpy scipy matplotlib qutip qiskit qiskit-aerpip install ShadowSim.py support is coming soon.
pip install -r requirements-test.txt
python -m pytest --cov=src --cov-config=.coveragerc --cov-report=term-missingPushes to main run the same in GitHub Actions and upload coverage to Codecov (enable the Codecov GitHub app for this repo the first time so uploads succeed).
The following simulators are supported by the package:
| Name | Type | Can handle open systems |
|---|---|---|
| Qutip simulator | classical | true |
| Split JMatrix | quantum-inspired | true |
| Trotterization (coming soon) | — | — |
| Wave matrix Lindbladization (coming soon) | — | — |
| Pauli propagation (coming soon) | — | — |
Imagine a scenario in which you want to compare the results of a new quantum simulation algorithm against a source of truth like QuTiP.
We first define some constants used in our system:
# Define system parameters
omega_c = 245000
omega_e = 245000
kappa = np.sqrt(24.5)
gamma = np.sqrt(0.4)
g = 100
a = (
np.outer(zero_state_two_qubits, one_state_two_qubits)
+ np.sqrt(2) * np.outer(one_state_two_qubits, two_state_two_qubits)
+ np.sqrt(3) * np.outer(two_state_two_qubits, three_state_two_qubits)
)
zero = np.array([1, 0], dtype=np.complex128)
one = np.array([0, 1], dtype=np.complex128)
sigma = np.outer(zero, one)Now that the system constants are built, let's define our operators. Since this is an open-system simulation we have both Hamiltonians and Lindblad operators.
H1 = omega_c * a.conjugate().T @ a
H2 = omega_e * np.outer(one, one)
H3 = g * (np.kron(a, sigma.conjugate().T) + np.kron(a.conjugate().T, sigma))
local_hamiltonians = [
LocalHamiltonian(H1, [0, 1]),
LocalHamiltonian(H2, [2]),
LocalHamiltonian(H3, [0, 1, 2]),
]
full_hamiltonians = [
Hamiltonian(tensor([H1, I])),
Hamiltonian(tensor([I, I, H2])),
Hamiltonian(H3),
]
# Define Lindblad operators
L1_full = Operator(kappa * np.kron(a, I))
L2_full = Operator(gamma * (tensor([I, I, sigma])))
L1_local = LocalOperator(kappa * a, [0, 1])
L2_local = LocalOperator(gamma * sigma, [2])
# Define initial state
psi_0 = State(tensor([two_state_two_qubits, zero]), 3)Next, we create two simulators, one for the new algorithm and one for the source of truth.
# Qutip simulator
qutip_simulator = QutipSimulator(
full_hamiltonians,
[L1_full, L2_full],
psi_0,
[
Operator(tensor([a.conjugate().T @ a, I])),
Operator(tensor([I, I, sigma.conjugate().T @ sigma])),
],
3,
0.25,
301,
)
# Split JMatrix simulator
splitjmatrix_simulator = SplitJMatrixSimulator(
local_hamiltonians,
[L1_local, L2_local],
psi_0,
3,
0.25,
301,
40,
measurement_groups=[[1, 2], 3],
reducers=[_cavity_population, _population_one],
)To easily compare results, we initialize a benchmark with both simulators. The two simulators must have the same time steps to compare apples to apples. We run the benchmark, which runs the underlying simulations. We can visualize the result by calling save_result_plot which saves the two simulation results and an absolute value comparison.
benchmark = Benchmark(qutip_simulator, splitjmatrix_simulator)
benchmark.run()
paths = benchmark.save_result_plot(labels=["cavity population", "emitter population"])
for path in paths:
print(f"Saved: {path}")Output
QuTiP (reference):
Split JMatrix:
Absolute difference between the two:
Contributions are welcome and appreciated.
- Fork the repository and clone your fork (see the Installation section).
- Create a feature branch:
git checkout -b feature/your-change- Make your changes and keep commits focused.
- Run tests and any relevant checks locally.
- Open a pull request with a clear description of what changed and why.
For larger changes, please open an issue first to discuss scope and design.
This project is licensed under the MIT License. See LICENSE for details.


