Ising model

A compact transverse-field Ising example using the same four-step pattern that underlies the rest of the DSL: iterate, filter if needed, emit updates, and compile.

We consider the one-dimensional transverse-field Ising Hamiltonian

\[H = J \sum_{\langle i,j \rangle} \sigma_i^z \sigma_j^z - h \sum_i \sigma_i^x\]

The first term is diagonal in the computational basis. The second flips one spin at a time. In the DSL that becomes one bond iterator emitting identity() branches and one site iterator emitting a single-site rewrite.

Setup

import netket as nk
import nkdsl

L = 6
J = 1.2
h = 0.7

hi = nk.hilbert.Spin(s=0.5, N=L)
g = nk.graph.Chain(length=L, pbc=True)
edges = g.edges()
∣NK⟩ Tip: Prefer the new nk.driver.VMC_SR over VMC which supports minSR and SPRING.

Construct the symbolic operator

H = (
    nkdsl.SymbolicDiscreteJaxOperator(hi, "ising_sym", hermitian=True)
    .for_each(("i", "j"), over=edges)
    .emit(
        nkdsl.identity(),
        matrix_element=J * nkdsl.site("i").value * nkdsl.site("j").value,
    )
    .for_each_site("i")
    .emit(
        nkdsl.write("i", -nkdsl.site("i").value),
        matrix_element=-h,
    )
    .compile()
)

Construct the state

model = nk.models.RBM(alpha=1, param_dtype=float)
state = nk.vqs.FullSumState(hi, model, seed=101)
opt = nk.optimizer.Sgd(learning_rate=0.01)
driver = nk.driver.VMC(H, opt, variational_state=state)

Run the VMC

driver.run(50, out=None, show_progress=False, timeit=True)
print("Final energy statistics:", state.expect(H))

╭────────────────────────────────────────────── Timing Information ───────────────────────────────────────────────╮
│ Total: 0.384                                                                                                    │
│ └── (92.2%) | VMC._forward_and_backward : 0.354 s                                                               │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Final energy statistics: -4.580e+00 [σ²=8.4e+00]

Compare with NetKet native

Operator

ising_nk = nk.operator.IsingJax(hi, g, h=h, J=J)

State

model = nk.models.RBM(alpha=1, param_dtype=float)
state = nk.vqs.FullSumState(hi, model, seed=101)
opt = nk.optimizer.Sgd(learning_rate=0.01)
driver = nk.driver.VMC(ising_nk, opt, variational_state=state)

VMC

driver.run(50, out=None, show_progress=False, timeit=True)
print("Final energy statistics:", state.expect(ising_nk))

╭────────────────────────────────────────────── Timing Information ───────────────────────────────────────────────╮
│ Total: 0.058                                                                                                    │
│ └── (73.4%) | VMC._forward_and_backward : 0.043 s                                                               │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Final energy statistics: -4.580e+00 [σ²=8.4e+00]

What this notebook shows

This is the complete nkdsl workflow in one place.

  1. Define a Hilbert space and a static set of tuples to iterate over.

  2. Build the Hamiltonian declaratively with iterators, predicates, and emissions.

  3. Compile the symbolic description into a NetKet-compatible JAX operator.

  4. Optimise a variational state directly against that compiled operator.