Minimal examples#
This page collects short examples that are useful in notebooks and tests. They avoid optional plotting or distributed dependencies unless explicitly noted.
Square QDM Hamiltonian#
from qlinks.models import SquareQDMModel
model = SquareQDMModel(
lx=4,
ly=4,
boundary_condition="periodic",
winding_x=0,
winding_y=0,
coup_kin=1.0,
coup_pot=1.0,
)
result = model.build(builder="sparse", basis_solver="dfs")
print(result.basis.n_states)
print(result.hamiltonian.shape)
print(result.kinetic.nnz)
Square QLM with staggered background charges#
Honeycomb and some QLM setups can have an empty zero-charge constrained Hilbert space. For square QLM examples that are meant to compare with QDM-like physics, staggered charges are often useful:
from qlinks.models import SquareQLMModel
model = SquareQLMModel.from_staggered_background(
lx=4,
ly=4,
boundary_condition="periodic",
charge_magnitude=1,
winding_x=0,
winding_y=0,
coup_kin=1.0,
coup_pot=0.0,
)
result = model.build(builder="optimized", basis_solver="dfs")
print(result.hamiltonian.shape)
Plaquette-dependent couplings and Peierls phases#
Kinetic and potential couplings may be uniform values, dictionaries, or helper objects. Directed plaquette couplings are useful when a clockwise and anticlockwise move should carry complex-conjugate amplitudes:
from qlinks.models import DirectedPlaquetteCoupling, SquareQDMModel
coup_kin = {
0: DirectedPlaquetteCoupling(clockwise=1.0j, anticlockwise=-1.0j),
1: 1.0,
}
model = SquareQDMModel(
lx=2,
ly=2,
boundary_condition="periodic",
coup_kin=coup_kin,
coup_pot=0.0,
)
result = model.build(builder="sparse")
assert result.hamiltonian.shape[0] == result.basis.n_states
Reuse a basis across builders#
When checking two builders against one another, reuse the basis to make the row and column order identical:
sparse_result = model.build(builder="sparse", sort_basis=True)
bitmask_result = model.build(
builder="bitmask",
basis=sparse_result.basis,
sort_basis=False,
)
difference = sparse_result.hamiltonian - bitmask_result.hamiltonian
print(difference.nnz)
Alternatively, build both with sorting enabled and explicitly assert that the basis configurations match before comparing matrices.
Cage search and first record#
from qlinks.caging import CageSearchConfig, CageSearcher
build_result = model.build(builder="sparse", basis_solver="dfs")
search_result = CageSearcher.from_model_build_result(
build_result,
config=CageSearchConfig(search_type="type1", type1_kappas=(0,)),
).run()
if len(search_result) > 0:
record = search_result.first()
print(record.signature)
print(record.support)
Reduced density matrix readout#
The caging diagnostics layer can inspect a state on a chosen set of variables:
from qlinks.caging import local_reduced_density_matrix_readout_from_state
readout = local_reduced_density_matrix_readout_from_state(
basis_configs=build_result.basis.states,
state=record.full_state,
variable_indices=(0, 1),
)
print(readout.local_basis)
print(readout.density_matrix)
The exact choice of variable_indices depends on the physical diagnostic you
want. For interference-zero reports, prefer the local supports returned by the
classification layer rather than manually selecting variables.
Open-system time evolution#
For a small dense or sparse problem, the open-system module provides helpers for initial states and Lindblad evolution:
import numpy as np
from qlinks.open_system import density_matrix_from_state, solve_lindblad
state = np.zeros(build_result.hamiltonian.shape[0], dtype=np.complex128)
state[0] = 1.0
rho0 = density_matrix_from_state(state)
times = np.linspace(0.0, 1.0, 51)
trajectory = solve_lindblad(
hamiltonian=build_result.hamiltonian,
jumps=(),
density_matrix_initial=rho0,
times=times,
method="rk4_liouville",
)
print(trajectory.density_matrices[-1].shape)