qlinks.models package#
Submodules#
qlinks.models.base module#
- qlinks.models.base.normalize_sector_label_for_display(label)[source]#
Normalize sector labels exposed by model-level APIs.
Fractions with denominator 1 are converted to ints recursively. Other Fractions are kept exact.
- Parameters:
label (Any)
- Return type:
Any
- qlinks.models.base.normalize_sector_labels_for_display(labels)[source]#
Normalize a collection of model-facing sector labels.
- Parameters:
labels (Any)
- Return type:
Any
- class qlinks.models.base.HamiltonianTermSpec(name, operators, kind='other')[source]#
Bases:
objectA symbolic Hamiltonian term before matrix construction.
Examples
- kinetic term:
- HamiltonianTermSpec(
name=”kinetic”, kind=”kinetic”, operators=(op0, op1, …),
)
- potential term:
- HamiltonianTermSpec(
name=”potential”, kind=”potential”, operators=(diag_op0, diag_op1, …),
)
- Parameters:
name (str)
operators (tuple[object, ...])
kind (Literal['kinetic', 'potential', 'other'])
- name: str#
- operators: tuple[object, ...]#
- kind: Literal['kinetic', 'potential', 'other']#
- classmethod from_operators(name, operators, *, kind='other')[source]#
- Parameters:
name (str)
operators (Sequence[object])
kind (Literal['kinetic', 'potential', 'other'])
- Return type:
- property is_empty: bool#
- __init__(name, operators, kind='other')#
- Parameters:
name (str)
operators (tuple[object, ...])
kind (Literal['kinetic', 'potential', 'other'])
- Return type:
None
- class qlinks.models.base.BuiltHamiltonianTerm(name, kind, operators, matrix)[source]#
Bases:
objectA Hamiltonian term after sparse matrix construction.
- Parameters:
name (str)
kind (Literal['kinetic', 'potential', 'other'])
operators (tuple[object, ...])
matrix (Any | None)
- name: str#
- kind: Literal['kinetic', 'potential', 'other']#
- operators: tuple[object, ...]#
- matrix: Any | None#
- __init__(name, kind, operators, matrix)#
- Parameters:
name (str)
kind (Literal['kinetic', 'potential', 'other'])
operators (tuple[object, ...])
matrix (Any | None)
- Return type:
None
- class qlinks.models.base.ModelBuildResult(model, lattice, layout, constraints, sectors, basis, terms, hamiltonian)[source]#
Bases:
objectFull model build result.
The intended usage is:
result = model.build(…) H = result.hamiltonian K = result.kinetic V = result.potential basis = result.basis
This avoids repeatedly calling expensive build methods.
- Parameters:
model (object)
lattice (object)
layout (VariableLayout)
constraints (tuple[Constraint, ...])
sectors (tuple[SectorCondition, ...])
basis (Basis | BinaryEncodedBasis)
terms (dict[str, BuiltHamiltonianTerm])
hamiltonian (Any)
- model: object#
- lattice: object#
- layout: VariableLayout#
- constraints: tuple[Constraint, ...]#
- sectors: tuple[SectorCondition, ...]#
- basis: Basis | BinaryEncodedBasis#
- terms: dict[str, BuiltHamiltonianTerm]#
- hamiltonian: Any#
- property kinetic: Any | None#
- property potential: Any | None#
- property kinetic_operators: tuple[object, ...]#
- property potential_operators: tuple[object, ...]#
- property operators: tuple[object, ...]#
- __init__(model, lattice, layout, constraints, sectors, basis, terms, hamiltonian)#
- Parameters:
model (object)
lattice (object)
layout (VariableLayout)
constraints (tuple[Constraint, ...])
sectors (tuple[SectorCondition, ...])
basis (Basis | BinaryEncodedBasis)
terms (dict[str, BuiltHamiltonianTerm])
hamiltonian (Any)
- Return type:
None
- class qlinks.models.base.SparseBuildOptions(backend='scipy', dtype=<class 'numpy.complex128'>, on_missing='raise', drop_zero_atol=0.0)[source]#
Bases:
objectShared sparse-build options.
This is mostly a convenience container for scripts and future APIs.
- Parameters:
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- backend: Literal['scipy', 'cupy', 'auto'] | SparseBackend#
- dtype: DTypeLike#
- on_missing: Literal['skip', 'raise']#
- drop_zero_atol: float#
- __init__(backend='scipy', dtype=<class 'numpy.complex128'>, on_missing='raise', drop_zero_atol=0.0)#
- Parameters:
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
None
- qlinks.models.base.solve_basis(layout, constraints=(), sectors=(), *, solver='dfs', sort=True, max_states=None)[source]#
Common array-basis solver dispatch.
If no constraints/sectors are present, use a direct Cartesian-product construction instead of DFS/CP-SAT/brute force.
- Parameters:
layout (VariableLayout)
constraints (Sequence[Constraint])
sectors (Sequence[SectorCondition])
solver (Literal['brute_force', 'dfs', 'cpsat'])
sort (bool)
max_states (int | None)
- Return type:
- qlinks.models.base.validate_builder_name(builder)[source]#
- Parameters:
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
None
- qlinks.models.base.combine_hamiltonian_terms(matrices)[source]#
Sum all non-None sparse matrices.
- Raises:
ValueError – If all terms are None.
- Parameters:
matrices (Sequence[Any | None])
- Return type:
Any
- class qlinks.models.base.HamiltonianModelBase[source]#
Bases:
objectBase class for Hamiltonian models.
Concrete models should implement:
_make_lattice() _make_layout() make_constraints() make_sectors() make_terms()
The base class provides:
cached lattice cached layout cached model_builder build_basis() build() build_hamiltonian()
Notes
Model classes that inherit from this base should usually NOT use dataclass(slots=True), because functools.cached_property needs an instance __dict__. Use:
@dataclass(frozen=True) class MyModel(HamiltonianModelBase):
…
- property layout: VariableLayout[source]#
- property model_builder: GenericModelBuilder[source]#
- allowed_sector_labels()[source]#
Return allowed user-facing quantum labels for diagonal symmetry sectors.
Models without user-selectable sectors return an empty dictionary. Geometry-specific subclasses should override this method.
Examples
SquareQLMModel(…).allowed_sector_labels()
may return:
- {
“winding_x”: (…), “winding_y”: (…),
}
- Return type:
dict[str, tuple[object, …]]
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- Return type:
Sequence[Constraint]
- make_sectors(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- Return type:
Sequence[SectorCondition]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
Sequence[HamiltonianTermSpec]
- prepare_builder_basis(*, physical_layout, array_basis, input_basis, builder, sort_basis)[source]#
Convert the physical layout/basis into the representation needed by the requested builder.
Default behavior#
- sparse / optimized:
use the array Basis.
- bitmask:
convert binary array Basis into BinaryEncodedBasis.
QLM flux models using {-1,+1} variables should override this method because they need the flux-to-binary encoding convention.
- Parameters:
physical_layout (VariableLayout)
array_basis (Basis)
input_basis (Basis | BinaryEncodedBasis | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
sort_basis (bool)
- Return type:
tuple[VariableLayout, Basis | BinaryEncodedBasis]
- has_basis_state(*, solver='dfs')[source]#
- Parameters:
solver (Literal['brute_force', 'dfs', 'cpsat'])
- Return type:
bool
- build_basis(*, solver='dfs', sort=True, max_states=None)[source]#
- Parameters:
solver (Literal['brute_force', 'dfs', 'cpsat'])
sort (bool)
max_states (int | None)
- Return type:
- build(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
Build basis, Hamiltonian terms, and total Hamiltonian once.
Preferred usage:
result = model.build(…) H = result.hamiltonian K = result.kinetic V = result.potential
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
- build_hamiltonian(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
Convenience method returning only the total Hamiltonian.
For accessing kinetic/potential separately, prefer calling build() once and using result.kinetic/result.potential.
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
Any
- local_term_descriptors(*, operator_kind=None, term_kind=None)[source]#
Return matrix-free descriptors for local Hamiltonian pieces.
The default is empty because not every model exposes local terms yet. Geometry-specific models should override this.
- Parameters:
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'] | None)
term_kind (Literal['plaquette', 'site', 'link', 'bond'] | None)
- Return type:
tuple[LocalTermDescriptor, …]
- make_local_term(descriptor, layout, *, builder='sparse')[source]#
Return the operator spec for one local term.
Subclasses implementing local_term_descriptors() should also implement this.
- Parameters:
descriptor (LocalTermDescriptor)
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
- build_local_term(descriptor, build_result, *, builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, on_missing='raise', drop_zero_atol=0.0)[source]#
Build one local sparse matrix in the basis of an existing build result.
- Parameters:
descriptor (LocalTermDescriptor)
build_result (ModelBuildResult)
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
Any
- class qlinks.models.base.GenericModelBuilder(model)[source]#
Bases:
objectShared Hamiltonian model builder.
It owns the repeated model-building workflow:
get cached layout
build constraints/sectors
solve or convert basis
ask model for Hamiltonian terms
build each sparse term matrix
sum terms into total Hamiltonian
return ModelBuildResult
- Parameters:
model (HamiltonianModelBase)
- model: HamiltonianModelBase#
- build_basis(*, solver='dfs', sort=True, max_states=None)[source]#
- Parameters:
solver (Literal['brute_force', 'dfs', 'cpsat'])
sort (bool)
max_states (int | None)
- Return type:
- build(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
- build_hamiltonian(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
Any
- __init__(model)#
- Parameters:
model (HamiltonianModelBase)
- Return type:
None
qlinks.models.pxp module#
- class qlinks.models.pxp.PXPModel(lattice_input, omega=1.0)[source]#
Bases:
HamiltonianModelBasePXP/Rydberg blockade model.
- Variables:
binary site occupations n_i in {0, 1}
- Constraint:
no two neighboring sites can both be occupied.
- Hamiltonian:
H = omega * sum_i P_neighbors X_i P_neighbors
The constrained basis already enforces the blockade, and the operator applies spin flips only when neighboring sites are unoccupied.
- Parameters:
lattice_input (ChainLattice | SquareLattice)
omega (complex)
- lattice_input: ChainLattice | SquareLattice#
- omega: complex = 1.0#
- classmethod chain(length, *, boundary_condition=BoundaryCondition.OPEN, omega=1.0)[source]#
- Parameters:
length (int)
boundary_condition (BoundaryCondition | str)
omega (complex)
- Return type:
- classmethod square(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, omega=1.0)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
omega (complex)
- Return type:
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- __init__(lattice_input, omega=1.0)#
- Parameters:
lattice_input (ChainLattice | SquareLattice)
omega (complex)
- Return type:
None
qlinks.models.qdm module#
- class qlinks.models.qdm.QDMBase(coup_kin=-1.0, coup_pot=0.0, required_count=1)[source]#
Bases:
HamiltonianModelBaseShared implementation for link-binary quantum dimer models.
Subclasses provide the lattice geometry by implementing _make_lattice(). They may also override plaquette_ids() or make_sectors() for geometry-specific topological sectors.
- Variables:
n_l in {0, 1}
- Constraint:
sum of occupied links touching each site = required_count
- Hamiltonian:
- H = kinetic * sum_p flip_p
potential * sum_p flippability_p
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- coup_kin: DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex] = -1.0#
- coup_pot: complex | Mapping[int, complex] | Callable[[int], complex] = 0.0#
- required_count: int = 1#
- allowed_sector_labels()[source]#
Return allowed user-facing quantum labels for diagonal symmetry sectors.
Models without user-selectable sectors return an empty dictionary. Geometry-specific subclasses should override this method.
Examples
SquareQLMModel(…).allowed_sector_labels()
may return:
- {
“winding_x”: (…), “winding_y”: (…),
}
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_kinetic_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_potential_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- local_term_descriptors(*, operator_kind=None, term_kind=None)[source]#
Return matrix-free descriptors for local Hamiltonian pieces.
The default is empty because not every model exposes local terms yet. Geometry-specific models should override this.
- Parameters:
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'] | None)
term_kind (Literal['plaquette', 'site', 'link', 'bond'] | None)
- Return type:
tuple[LocalTermDescriptor, …]
- make_local_term(descriptor, layout, *, builder='sparse')[source]#
Return the operator spec for one local term.
Subclasses implementing local_term_descriptors() should also implement this.
- Parameters:
descriptor (LocalTermDescriptor)
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- Return type:
None
- class qlinks.models.qdm.SquareQDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None, winding_convention='electric')[source]#
Bases:
QDMBaseSquare-lattice quantum dimer model.
This subclass keeps square-specific functionality, especially winding sectors.
- winding_convention:
- “cut_count”:
raw count of occupied wrapping links.
- “electric”:
staggered electric-flux winding compatible with the square QDM to staggered-charge QLM mapping.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
winding_convention (Literal['cut_count', 'electric'])
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- winding_convention: Literal['cut_count', 'electric'] = 'electric'#
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None, winding_convention='electric')#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
winding_convention (Literal['cut_count', 'electric'])
- Return type:
None
- class qlinks.models.qdm.TriangularQDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)[source]#
Bases:
QDMBaseTriangular-lattice QDM.
The QDM resonance plaquettes are rhombi/lozenges, not elementary triangles.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_a: int | None = None#
- winding_b: int | None = None#
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- Return type:
None
- class qlinks.models.qdm.HoneycombQDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)[source]#
Bases:
QDMBaseHoneycomb-lattice QDM.
The QDM resonance plaquettes are hexagons.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- Return type:
None
- class qlinks.models.qdm.QDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lattice_input=None)[source]#
Bases:
QDMBaseGeneric lattice-backed QDM model.
Use this when you already have a LatticeGraph instance.
- For named geometries, prefer:
SquareQDMModel TriangularQDMModel HoneycombQDMModel
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lattice_input (LatticeGraph | None)
- lattice_input: LatticeGraph | None = None#
- classmethod triangular(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, required_count=1)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- Return type:
- classmethod honeycomb(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, required_count=1)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lattice_input=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lattice_input (LatticeGraph | None)
- Return type:
None
qlinks.models.qlm module#
- class qlinks.models.qlm.QLMBase(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half')[source]#
Bases:
HamiltonianModelBaseShared implementation for spin-1/2 quantum link models.
- Variables:
link electric flux E_l in {-1, +1}
- Constraint:
Gauss law at each site.
- Hamiltonian:
- H = kinetic * sum_p ring_exchange_p
potential * sum_p flippability_p
- Bitmask convention:
- physical flux:
-1, +1
- encoded binary:
-1 -> 0 +1 -> 1
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
- coup_kin: DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex] = -1.0#
- coup_pot: complex | Mapping[int, complex] | Callable[[int], complex] = 0.0#
- charge_normalization: Literal['integer_flux', 'spin_half'] = 'spin_half'#
- allowed_sector_labels()[source]#
Return allowed user-facing quantum labels for diagonal symmetry sectors.
Models without user-selectable sectors return an empty dictionary. Geometry-specific subclasses should override this method.
Examples
SquareQLMModel(…).allowed_sector_labels()
may return:
- {
“winding_x”: (…), “winding_y”: (…),
}
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- prepare_builder_basis(*, physical_layout, array_basis, input_basis, builder, sort_basis)[source]#
Override the default bitmask conversion because physical QLM variables are {-1,+1}, while the bitmask backend needs binary {0,1}.
- Parameters:
physical_layout (VariableLayout)
array_basis (Basis)
input_basis (Basis | BinaryEncodedBasis | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
sort_basis (bool)
- Return type:
tuple[VariableLayout, Basis | BinaryEncodedBasis]
- make_kinetic_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_potential_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- local_term_descriptors(*, operator_kind=None, term_kind=None)[source]#
Return matrix-free descriptors for local Hamiltonian pieces.
The default is empty because not every model exposes local terms yet. Geometry-specific models should override this.
- Parameters:
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'] | None)
term_kind (Literal['plaquette', 'site', 'link', 'bond'] | None)
- Return type:
tuple[LocalTermDescriptor, …]
- make_local_term(descriptor, layout, *, builder='sparse')[source]#
Return the operator spec for one local term.
Subclasses implementing local_term_descriptors() should also implement this.
- Parameters:
descriptor (LocalTermDescriptor)
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half')#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
- Return type:
None
- class qlinks.models.qlm.SquareQLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)[source]#
Bases:
QLMBaseSquare-lattice spin-1/2 QLM.
- Square-specific functionality:
square lattice construction
optional winding sectors
optimized update operators for the kinetic term
specialized bitmask QLM flux flip/projectors
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- classmethod from_staggered_background(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charge_magnitude=None, charge_convention='even_positive', charge_normalization='spin_half', winding_x=None, winding_y=None)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charge_magnitude (int | None)
charge_convention (Literal['even_positive', 'odd_positive'])
charge_normalization (Literal['integer_flux', 'spin_half'])
winding_x (int | None)
winding_y (int | None)
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- Return type:
None
- class qlinks.models.qlm.TriangularQLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)[source]#
Bases:
QLMBaseTriangular-lattice QLM.
By default, QLM ring exchange uses rhombus/lozenge plaquettes rather than elementary triangular loops, because the alternating flux pattern requires even-length loops.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_a: int | None = None#
- winding_b: int | None = None#
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- Return type:
None
- class qlinks.models.qlm.HoneycombQLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)[source]#
Bases:
QLMBaseHoneycomb-lattice QLM.
The ring-exchange plaquettes are hexagons.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- classmethod staggered_background_charges(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, charge_magnitude=1, charge_convention='even_positive')[source]#
Return staggered honeycomb background charges.
For the honeycomb spin-1/2 QLM with integer-flux variables E_l = ±1, each bulk site has degree 3, so allowed local charges are odd: ±1 or ±3.
- Sublattice convention:
sublattice 0 = A sublattice 1 = B
- charge_convention:
- “even_positive”:
A sites carry +charge_magnitude, B sites carry -charge_magnitude.
- “even_negative”:
A sites carry -charge_magnitude, B sites carry +charge_magnitude.
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
charge_magnitude (int)
charge_convention (Literal['even_positive', 'odd_positive'])
- Return type:
- classmethod from_staggered_background(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charge_magnitude=1, charge_convention='even_positive', winding_x=None, winding_y=None)[source]#
Construct a honeycomb QLM with staggered ±1 or ±3 charges.
Uses charge_normalization=’integer_flux’ because honeycomb spin-1/2 Gauss law needs odd internal charge targets.
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charge_magnitude (int)
charge_convention (Literal['even_positive', 'odd_positive'])
winding_x (int | None)
winding_y (int | None)
- Return type:
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- Return type:
None
- class qlinks.models.qlm.QLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lattice_input=None)[source]#
Bases:
QLMBaseGeneric lattice-backed QLM model.
Use this when you already have a LatticeGraph instance.
- For named geometries, prefer:
SquareQLMModel TriangularQLMModel HoneycombQLMModel
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lattice_input (LatticeGraph | None)
- lattice_input: LatticeGraph | None = None#
- classmethod triangular(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charges=0)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
- Return type:
- classmethod honeycomb(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charges=0)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lattice_input=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lattice_input (LatticeGraph | None)
- Return type:
None
Module contents#
- class qlinks.models.BuiltHamiltonianTerm(name, kind, operators, matrix)[source]#
Bases:
objectA Hamiltonian term after sparse matrix construction.
- Parameters:
name (str)
kind (Literal['kinetic', 'potential', 'other'])
operators (tuple[object, ...])
matrix (Any | None)
- name: str#
- kind: Literal['kinetic', 'potential', 'other']#
- operators: tuple[object, ...]#
- matrix: Any | None#
- __init__(name, kind, operators, matrix)#
- Parameters:
name (str)
kind (Literal['kinetic', 'potential', 'other'])
operators (tuple[object, ...])
matrix (Any | None)
- Return type:
None
- class qlinks.models.GenericModelBuilder(model)[source]#
Bases:
objectShared Hamiltonian model builder.
It owns the repeated model-building workflow:
get cached layout
build constraints/sectors
solve or convert basis
ask model for Hamiltonian terms
build each sparse term matrix
sum terms into total Hamiltonian
return ModelBuildResult
- Parameters:
model (HamiltonianModelBase)
- model: HamiltonianModelBase#
- build_basis(*, solver='dfs', sort=True, max_states=None)[source]#
- Parameters:
solver (Literal['brute_force', 'dfs', 'cpsat'])
sort (bool)
max_states (int | None)
- Return type:
- build(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
- build_hamiltonian(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
Any
- __init__(model)#
- Parameters:
model (HamiltonianModelBase)
- Return type:
None
- class qlinks.models.HamiltonianModelBase[source]#
Bases:
objectBase class for Hamiltonian models.
Concrete models should implement:
_make_lattice() _make_layout() make_constraints() make_sectors() make_terms()
The base class provides:
cached lattice cached layout cached model_builder build_basis() build() build_hamiltonian()
Notes
Model classes that inherit from this base should usually NOT use dataclass(slots=True), because functools.cached_property needs an instance __dict__. Use:
@dataclass(frozen=True) class MyModel(HamiltonianModelBase):
…
- property layout: VariableLayout[source]#
- property model_builder: GenericModelBuilder[source]#
- allowed_sector_labels()[source]#
Return allowed user-facing quantum labels for diagonal symmetry sectors.
Models without user-selectable sectors return an empty dictionary. Geometry-specific subclasses should override this method.
Examples
SquareQLMModel(…).allowed_sector_labels()
may return:
- {
“winding_x”: (…), “winding_y”: (…),
}
- Return type:
dict[str, tuple[object, …]]
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- Return type:
Sequence[Constraint]
- make_sectors(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- Return type:
Sequence[SectorCondition]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
Sequence[HamiltonianTermSpec]
- prepare_builder_basis(*, physical_layout, array_basis, input_basis, builder, sort_basis)[source]#
Convert the physical layout/basis into the representation needed by the requested builder.
Default behavior#
- sparse / optimized:
use the array Basis.
- bitmask:
convert binary array Basis into BinaryEncodedBasis.
QLM flux models using {-1,+1} variables should override this method because they need the flux-to-binary encoding convention.
- Parameters:
physical_layout (VariableLayout)
array_basis (Basis)
input_basis (Basis | BinaryEncodedBasis | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
sort_basis (bool)
- Return type:
tuple[VariableLayout, Basis | BinaryEncodedBasis]
- has_basis_state(*, solver='dfs')[source]#
- Parameters:
solver (Literal['brute_force', 'dfs', 'cpsat'])
- Return type:
bool
- build_basis(*, solver='dfs', sort=True, max_states=None)[source]#
- Parameters:
solver (Literal['brute_force', 'dfs', 'cpsat'])
sort (bool)
max_states (int | None)
- Return type:
- build(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
Build basis, Hamiltonian terms, and total Hamiltonian once.
Preferred usage:
result = model.build(…) H = result.hamiltonian K = result.kinetic V = result.potential
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
- build_hamiltonian(*, basis=None, basis_solver='dfs', builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, sort_basis=True, on_missing='raise', drop_zero_atol=0.0)[source]#
Convenience method returning only the total Hamiltonian.
For accessing kinetic/potential separately, prefer calling build() once and using result.kinetic/result.potential.
- Parameters:
basis (Basis | BinaryEncodedBasis | None)
basis_solver (Literal['brute_force', 'dfs', 'cpsat'])
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
sort_basis (bool)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
Any
- local_term_descriptors(*, operator_kind=None, term_kind=None)[source]#
Return matrix-free descriptors for local Hamiltonian pieces.
The default is empty because not every model exposes local terms yet. Geometry-specific models should override this.
- Parameters:
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'] | None)
term_kind (Literal['plaquette', 'site', 'link', 'bond'] | None)
- Return type:
tuple[LocalTermDescriptor, …]
- make_local_term(descriptor, layout, *, builder='sparse')[source]#
Return the operator spec for one local term.
Subclasses implementing local_term_descriptors() should also implement this.
- Parameters:
descriptor (LocalTermDescriptor)
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
- build_local_term(descriptor, build_result, *, builder='sparse', backend='scipy', dtype=<class 'numpy.complex128'>, on_missing='raise', drop_zero_atol=0.0)[source]#
Build one local sparse matrix in the basis of an existing build result.
- Parameters:
descriptor (LocalTermDescriptor)
build_result (ModelBuildResult)
builder (Literal['sparse', 'optimized', 'bitmask'])
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
Any
- class qlinks.models.HamiltonianTermSpec(name, operators, kind='other')[source]#
Bases:
objectA symbolic Hamiltonian term before matrix construction.
Examples
- kinetic term:
- HamiltonianTermSpec(
name=”kinetic”, kind=”kinetic”, operators=(op0, op1, …),
)
- potential term:
- HamiltonianTermSpec(
name=”potential”, kind=”potential”, operators=(diag_op0, diag_op1, …),
)
- Parameters:
name (str)
operators (tuple[object, ...])
kind (Literal['kinetic', 'potential', 'other'])
- name: str#
- operators: tuple[object, ...]#
- kind: Literal['kinetic', 'potential', 'other']#
- classmethod from_operators(name, operators, *, kind='other')[source]#
- Parameters:
name (str)
operators (Sequence[object])
kind (Literal['kinetic', 'potential', 'other'])
- Return type:
- property is_empty: bool#
- __init__(name, operators, kind='other')#
- Parameters:
name (str)
operators (tuple[object, ...])
kind (Literal['kinetic', 'potential', 'other'])
- Return type:
None
- class qlinks.models.LocalTermDescriptor(term_id, term_kind, operator_kind, support_links, support_sites=(), support_plaquettes=(), label=None)[source]#
Bases:
objectGeometry-level descriptor for one local operator term.
This descriptor is intentionally matrix-free. It tells us which local term we want, where it lives in real space, and which model method should assemble it.
- Parameters:
term_id (int)
term_kind (Literal['plaquette', 'site', 'link', 'bond'])
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'])
support_links (tuple[int, ...])
support_sites (tuple[int, ...])
support_plaquettes (tuple[int, ...])
label (str | None)
- term_id: int#
- term_kind: Literal['plaquette', 'site', 'link', 'bond']#
- operator_kind: Literal['kinetic', 'potential', 'hamiltonian']#
- support_links: tuple[int, ...]#
- support_sites: tuple[int, ...]#
- support_plaquettes: tuple[int, ...]#
- label: str | None#
- property support_link_set: frozenset[int]#
- is_disjoint_from_links(links)[source]#
- Parameters:
links (set[int] | frozenset[int])
- Return type:
bool
- __init__(term_id, term_kind, operator_kind, support_links, support_sites=(), support_plaquettes=(), label=None)#
- Parameters:
term_id (int)
term_kind (Literal['plaquette', 'site', 'link', 'bond'])
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'])
support_links (tuple[int, ...])
support_sites (tuple[int, ...])
support_plaquettes (tuple[int, ...])
label (str | None)
- Return type:
None
- class qlinks.models.ModelBuildResult(model, lattice, layout, constraints, sectors, basis, terms, hamiltonian)[source]#
Bases:
objectFull model build result.
The intended usage is:
result = model.build(…) H = result.hamiltonian K = result.kinetic V = result.potential basis = result.basis
This avoids repeatedly calling expensive build methods.
- Parameters:
model (object)
lattice (object)
layout (VariableLayout)
constraints (tuple[Constraint, ...])
sectors (tuple[SectorCondition, ...])
basis (Basis | BinaryEncodedBasis)
terms (dict[str, BuiltHamiltonianTerm])
hamiltonian (Any)
- model: object#
- lattice: object#
- layout: VariableLayout#
- constraints: tuple[Constraint, ...]#
- sectors: tuple[SectorCondition, ...]#
- basis: Basis | BinaryEncodedBasis#
- terms: dict[str, BuiltHamiltonianTerm]#
- hamiltonian: Any#
- property kinetic: Any | None#
- property potential: Any | None#
- property kinetic_operators: tuple[object, ...]#
- property potential_operators: tuple[object, ...]#
- property operators: tuple[object, ...]#
- __init__(model, lattice, layout, constraints, sectors, basis, terms, hamiltonian)#
- Parameters:
model (object)
lattice (object)
layout (VariableLayout)
constraints (tuple[Constraint, ...])
sectors (tuple[SectorCondition, ...])
basis (Basis | BinaryEncodedBasis)
terms (dict[str, BuiltHamiltonianTerm])
hamiltonian (Any)
- Return type:
None
- class qlinks.models.SparseBuildOptions(backend='scipy', dtype=<class 'numpy.complex128'>, on_missing='raise', drop_zero_atol=0.0)[source]#
Bases:
objectShared sparse-build options.
This is mostly a convenience container for scripts and future APIs.
- Parameters:
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- backend: Literal['scipy', 'cupy', 'auto'] | SparseBackend#
- dtype: DTypeLike#
- on_missing: Literal['skip', 'raise']#
- drop_zero_atol: float#
- __init__(backend='scipy', dtype=<class 'numpy.complex128'>, on_missing='raise', drop_zero_atol=0.0)#
- Parameters:
backend (Literal['scipy', 'cupy', 'auto'] | ~qlinks.backends.sparse.SparseBackend)
dtype (DTypeLike)
on_missing (Literal['skip', 'raise'])
drop_zero_atol (float)
- Return type:
None
- qlinks.models.combine_hamiltonian_terms(matrices)[source]#
Sum all non-None sparse matrices.
- Raises:
ValueError – If all terms are None.
- Parameters:
matrices (Sequence[Any | None])
- Return type:
Any
- qlinks.models.normalize_sector_label_for_display(label)[source]#
Normalize sector labels exposed by model-level APIs.
Fractions with denominator 1 are converted to ints recursively. Other Fractions are kept exact.
- Parameters:
label (Any)
- Return type:
Any
- qlinks.models.normalize_sector_labels_for_display(labels)[source]#
Normalize a collection of model-facing sector labels.
- Parameters:
labels (Any)
- Return type:
Any
- qlinks.models.solve_basis(layout, constraints=(), sectors=(), *, solver='dfs', sort=True, max_states=None)[source]#
Common array-basis solver dispatch.
If no constraints/sectors are present, use a direct Cartesian-product construction instead of DFS/CP-SAT/brute force.
- Parameters:
layout (VariableLayout)
constraints (Sequence[Constraint])
sectors (Sequence[SectorCondition])
solver (Literal['brute_force', 'dfs', 'cpsat'])
sort (bool)
max_states (int | None)
- Return type:
- qlinks.models.validate_builder_name(builder)[source]#
- Parameters:
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
None
- class qlinks.models.PXPModel(lattice_input, omega=1.0)[source]#
Bases:
HamiltonianModelBasePXP/Rydberg blockade model.
- Variables:
binary site occupations n_i in {0, 1}
- Constraint:
no two neighboring sites can both be occupied.
- Hamiltonian:
H = omega * sum_i P_neighbors X_i P_neighbors
The constrained basis already enforces the blockade, and the operator applies spin flips only when neighboring sites are unoccupied.
- Parameters:
lattice_input (ChainLattice | SquareLattice)
omega (complex)
- lattice_input: ChainLattice | SquareLattice#
- omega: complex = 1.0#
- classmethod chain(length, *, boundary_condition=BoundaryCondition.OPEN, omega=1.0)[source]#
- Parameters:
length (int)
boundary_condition (BoundaryCondition | str)
omega (complex)
- Return type:
- classmethod square(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, omega=1.0)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
omega (complex)
- Return type:
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- __init__(lattice_input, omega=1.0)#
- Parameters:
lattice_input (ChainLattice | SquareLattice)
omega (complex)
- Return type:
None
- class qlinks.models.QDMBase(coup_kin=-1.0, coup_pot=0.0, required_count=1)[source]#
Bases:
HamiltonianModelBaseShared implementation for link-binary quantum dimer models.
Subclasses provide the lattice geometry by implementing _make_lattice(). They may also override plaquette_ids() or make_sectors() for geometry-specific topological sectors.
- Variables:
n_l in {0, 1}
- Constraint:
sum of occupied links touching each site = required_count
- Hamiltonian:
- H = kinetic * sum_p flip_p
potential * sum_p flippability_p
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- coup_kin: DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex] = -1.0#
- coup_pot: complex | Mapping[int, complex] | Callable[[int], complex] = 0.0#
- required_count: int = 1#
- allowed_sector_labels()[source]#
Return allowed user-facing quantum labels for diagonal symmetry sectors.
Models without user-selectable sectors return an empty dictionary. Geometry-specific subclasses should override this method.
Examples
SquareQLMModel(…).allowed_sector_labels()
may return:
- {
“winding_x”: (…), “winding_y”: (…),
}
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_kinetic_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_potential_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- local_term_descriptors(*, operator_kind=None, term_kind=None)[source]#
Return matrix-free descriptors for local Hamiltonian pieces.
The default is empty because not every model exposes local terms yet. Geometry-specific models should override this.
- Parameters:
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'] | None)
term_kind (Literal['plaquette', 'site', 'link', 'bond'] | None)
- Return type:
tuple[LocalTermDescriptor, …]
- make_local_term(descriptor, layout, *, builder='sparse')[source]#
Return the operator spec for one local term.
Subclasses implementing local_term_descriptors() should also implement this.
- Parameters:
descriptor (LocalTermDescriptor)
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- Return type:
None
- class qlinks.models.QDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lattice_input=None)[source]#
Bases:
QDMBaseGeneric lattice-backed QDM model.
Use this when you already have a LatticeGraph instance.
- For named geometries, prefer:
SquareQDMModel TriangularQDMModel HoneycombQDMModel
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lattice_input (LatticeGraph | None)
- lattice_input: LatticeGraph | None = None#
- classmethod triangular(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, required_count=1)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- Return type:
- classmethod honeycomb(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, required_count=1)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lattice_input=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lattice_input (LatticeGraph | None)
- Return type:
None
- class qlinks.models.SquareQDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None, winding_convention='electric')[source]#
Bases:
QDMBaseSquare-lattice quantum dimer model.
This subclass keeps square-specific functionality, especially winding sectors.
- winding_convention:
- “cut_count”:
raw count of occupied wrapping links.
- “electric”:
staggered electric-flux winding compatible with the square QDM to staggered-charge QLM mapping.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
winding_convention (Literal['cut_count', 'electric'])
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- winding_convention: Literal['cut_count', 'electric'] = 'electric'#
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None, winding_convention='electric')#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
winding_convention (Literal['cut_count', 'electric'])
- Return type:
None
- class qlinks.models.SquareQLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)[source]#
Bases:
QLMBaseSquare-lattice spin-1/2 QLM.
- Square-specific functionality:
square lattice construction
optional winding sectors
optimized update operators for the kinetic term
specialized bitmask QLM flux flip/projectors
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- classmethod from_staggered_background(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charge_magnitude=None, charge_convention='even_positive', charge_normalization='spin_half', winding_x=None, winding_y=None)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charge_magnitude (int | None)
charge_convention (Literal['even_positive', 'odd_positive'])
charge_normalization (Literal['integer_flux', 'spin_half'])
winding_x (int | None)
winding_y (int | None)
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- Return type:
None
- class qlinks.models.HoneycombQDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)[source]#
Bases:
QDMBaseHoneycomb-lattice QDM.
The QDM resonance plaquettes are hexagons.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- Return type:
None
- class qlinks.models.TriangularQDMModel(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)[source]#
Bases:
QDMBaseTriangular-lattice QDM.
The QDM resonance plaquettes are rhombi/lozenges, not elementary triangles.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_a: int | None = None#
- winding_b: int | None = None#
- plaquette_ids()[source]#
Plaquettes used by the QDM resonance move.
The lattice may define qdm_plaquette_ids() to select only the relevant resonance loops. For example, triangular QDM should use rhombi rather than elementary triangles.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QDM sector list.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, required_count=1, lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
required_count (int)
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- Return type:
None
- class qlinks.models.QLMBase(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half')[source]#
Bases:
HamiltonianModelBaseShared implementation for spin-1/2 quantum link models.
- Variables:
link electric flux E_l in {-1, +1}
- Constraint:
Gauss law at each site.
- Hamiltonian:
- H = kinetic * sum_p ring_exchange_p
potential * sum_p flippability_p
- Bitmask convention:
- physical flux:
-1, +1
- encoded binary:
-1 -> 0 +1 -> 1
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
- coup_kin: DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex] = -1.0#
- coup_pot: complex | Mapping[int, complex] | Callable[[int], complex] = 0.0#
- charge_normalization: Literal['integer_flux', 'spin_half'] = 'spin_half'#
- allowed_sector_labels()[source]#
Return allowed user-facing quantum labels for diagonal symmetry sectors.
Models without user-selectable sectors return an empty dictionary. Geometry-specific subclasses should override this method.
Examples
SquareQLMModel(…).allowed_sector_labels()
may return:
- {
“winding_x”: (…), “winding_y”: (…),
}
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- prepare_builder_basis(*, physical_layout, array_basis, input_basis, builder, sort_basis)[source]#
Override the default bitmask conversion because physical QLM variables are {-1,+1}, while the bitmask backend needs binary {0,1}.
- Parameters:
physical_layout (VariableLayout)
array_basis (Basis)
input_basis (Basis | BinaryEncodedBasis | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
sort_basis (bool)
- Return type:
tuple[VariableLayout, Basis | BinaryEncodedBasis]
- make_kinetic_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_potential_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- local_term_descriptors(*, operator_kind=None, term_kind=None)[source]#
Return matrix-free descriptors for local Hamiltonian pieces.
The default is empty because not every model exposes local terms yet. Geometry-specific models should override this.
- Parameters:
operator_kind (Literal['kinetic', 'potential', 'hamiltonian'] | None)
term_kind (Literal['plaquette', 'site', 'link', 'bond'] | None)
- Return type:
tuple[LocalTermDescriptor, …]
- make_local_term(descriptor, layout, *, builder='sparse')[source]#
Return the operator spec for one local term.
Subclasses implementing local_term_descriptors() should also implement this.
- Parameters:
descriptor (LocalTermDescriptor)
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half')#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
- Return type:
None
- class qlinks.models.QLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lattice_input=None)[source]#
Bases:
QLMBaseGeneric lattice-backed QLM model.
Use this when you already have a LatticeGraph instance.
- For named geometries, prefer:
SquareQLMModel TriangularQLMModel HoneycombQLMModel
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lattice_input (LatticeGraph | None)
- lattice_input: LatticeGraph | None = None#
- classmethod triangular(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charges=0)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
- Return type:
- classmethod honeycomb(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charges=0)[source]#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
- Return type:
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lattice_input=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lattice_input (LatticeGraph | None)
- Return type:
None
- class qlinks.models.SpinOneXYChainModel(length, boundary_condition=BoundaryCondition.OPEN, j_xy=1.0, h_z=0.0, d_z=0.0)[source]#
Bases:
HamiltonianModelBaseSpin-1 XY chain in the S^z product basis.
Local basis:
m_i in {-1, 0, +1}
Hamiltonian:
- H = J_xy * sum_<ij> (S^x_i S^x_j + S^y_i S^y_j)
= J_xy/2 * sum_<ij> (S^+_i S^-_j + S^-_i S^+_j)
No constraints are imposed at this stage.
- Parameters:
length (int)
boundary_condition (BoundaryCondition | str)
j_xy (complex)
h_z (complex)
d_z (complex)
- length: int#
- boundary_condition: BoundaryCondition | str = 'open'#
- j_xy: complex = 1.0#
- h_z: complex = 0.0#
- d_z: complex = 0.0#
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_kinetic_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_potential_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- __init__(length, boundary_condition=BoundaryCondition.OPEN, j_xy=1.0, h_z=0.0, d_z=0.0)#
- Parameters:
length (int)
boundary_condition (BoundaryCondition | str)
j_xy (complex)
h_z (complex)
d_z (complex)
- Return type:
None
- class qlinks.models.ToricCodeModel(lx=2, ly=2, boundary_condition=BoundaryCondition.PERIODIC, electric=1.0, magnetic=1.0)[source]#
Bases:
HamiltonianModelBaseStandard toric code on a square lattice with PBC.
Variables live on links in the Z basis:
z_l in {-1, +1}
Hamiltonian:
H = -electric * sum_v A_v - magnetic * sum_p B_p
where A_v flips all incident links and B_p is diagonal in the Z basis.
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
electric (complex)
magnetic (complex)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'periodic'#
- electric: complex = 1.0#
- magnetic: complex = 1.0#
- make_constraints(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_sectors(layout=None)[source]#
- Parameters:
layout (VariableLayout | None)
- make_star_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_plaquette_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_operators(layout=None, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout | None)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[object, …]
- make_terms(layout, *, builder='sparse')[source]#
- Parameters:
layout (VariableLayout)
builder (Literal['sparse', 'optimized', 'bitmask'])
- Return type:
tuple[HamiltonianTermSpec, …]
- __init__(lx=2, ly=2, boundary_condition=BoundaryCondition.PERIODIC, electric=1.0, magnetic=1.0)#
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
electric (complex)
magnetic (complex)
- Return type:
None
- class qlinks.models.TriangularQLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)[source]#
Bases:
QLMBaseTriangular-lattice QLM.
By default, QLM ring exchange uses rhombus/lozenge plaquettes rather than elementary triangular loops, because the alternating flux pattern requires even-length loops.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_a: int | None = None#
- winding_b: int | None = None#
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_a=None, winding_b=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_a (int | None)
winding_b (int | None)
- Return type:
None
- class qlinks.models.HoneycombQLMModel(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)[source]#
Bases:
QLMBaseHoneycomb-lattice QLM.
The ring-exchange plaquettes are hexagons.
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- lx: int = 2#
- ly: int = 2#
- boundary_condition: BoundaryCondition | str = 'open'#
- winding_x: int | Fraction | str | None = None#
- winding_y: int | Fraction | str | None = None#
- classmethod staggered_background_charges(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, charge_magnitude=1, charge_convention='even_positive')[source]#
Return staggered honeycomb background charges.
For the honeycomb spin-1/2 QLM with integer-flux variables E_l = ±1, each bulk site has degree 3, so allowed local charges are odd: ±1 or ±3.
- Sublattice convention:
sublattice 0 = A sublattice 1 = B
- charge_convention:
- “even_positive”:
A sites carry +charge_magnitude, B sites carry -charge_magnitude.
- “even_negative”:
A sites carry -charge_magnitude, B sites carry +charge_magnitude.
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
charge_magnitude (int)
charge_convention (Literal['even_positive', 'odd_positive'])
- Return type:
- classmethod from_staggered_background(lx, ly, *, boundary_condition=BoundaryCondition.OPEN, coup_kin=-1.0, coup_pot=0.0, charge_magnitude=1, charge_convention='even_positive', winding_x=None, winding_y=None)[source]#
Construct a honeycomb QLM with staggered ±1 or ±3 charges.
Uses charge_normalization=’integer_flux’ because honeycomb spin-1/2 Gauss law needs odd internal charge targets.
- Parameters:
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
coup_kin (complex | Mapping[int, complex] | Callable[[int], complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charge_magnitude (int)
charge_convention (Literal['even_positive', 'odd_positive'])
winding_x (int | None)
winding_y (int | None)
- Return type:
- plaquette_ids()[source]#
Plaquettes used by QLM ring exchange.
The lattice may define qlm_plaquette_ids() to select only valid even-length ring-exchange loops.
- Return type:
list[int]
- make_sectors(layout=None)[source]#
Default QLM sectors.
Geometry-specific subclasses can override this.
- Parameters:
layout (VariableLayout | None)
- __init__(coup_kin=-1.0, coup_pot=0.0, charges=0, charge_normalization='spin_half', lx=2, ly=2, boundary_condition=BoundaryCondition.OPEN, winding_x=None, winding_y=None)#
- Parameters:
coup_kin (DirectedPlaquetteCoupling | complex | Mapping[int, DirectedPlaquetteCoupling | complex] | Callable[[int], DirectedPlaquetteCoupling | complex])
coup_pot (complex | Mapping[int, complex] | Callable[[int], complex])
charges (int | Sequence[int] | ndarray[tuple[Any, ...], dtype[int64]])
charge_normalization (Literal['integer_flux', 'spin_half'])
lx (int)
ly (int)
boundary_condition (BoundaryCondition | str)
winding_x (int | Fraction | str | None)
winding_y (int | Fraction | str | None)
- Return type:
None