Emissions and matrix elements

Each call to emit(...) adds one branch to the current term.

op = (
    SymbolicDiscreteJaxOperator(hi, "two_branch")
    .for_each_site("i")
    .where(site("i").abs() < 2)
    .emit(shift("i", +1), matrix_element=+0.5, tag="raise")
    .emit(shift("i", -1), matrix_element=-0.5, tag="lower")
    .build()
)

An emission contains:

  • an update program that maps x to x'

  • a matrix element expression

  • an optional diagnostic branch tag

Multi-emission semantics

Multiple emissions share the same iterator visit and predicate evaluation. This is often cleaner and cheaper than repeating the iterator block.

Conditional emission chains

nkDSL also supports if / elseif / else style branching at the emission level.

op = (
    SymbolicDiscreteJaxOperator(hi, "piecewise")
    .for_each_site("i")
    .emit_if(site("i") == 0, write("i", 1), matrix_element=1.0, tag="if")
    .emit_elseif(site("i") == 1, write("i", 2), matrix_element=2.0, tag="elseif")
    .emit_else(write("i", 3), matrix_element=3.0, tag="else")
    .build()
)

Chaining rules:

  • emit_if(...) starts a new conditional chain.

  • emit_elseif(...) extends the current chain.

  • emit_else(...) closes the current chain.

  • Calling plain emit(...) closes any currently open chain.

Active branches contribute candidate connected states. Before final padding, duplicate x' targets are coalesced (matrix elements summed) and zero-amplitude components are removed.

Connected-state dedup semantics

Connected states are deduplicated by default. If two branches emit the same x', they are merged into one row and their matrix elements are summed. Entries with final matrix element 0 are dropped before padding.

Set deduplicate_connected_components=False at compile time if you need raw per-branch connectivity output.

Source and emitted state access

Matrix elements can depend on both the source configuration and the emitted configuration.

  • site("i") reads from x

  • emitted("i") reads from x'

This is especially useful when amplitudes depend on the value after a rewrite.

Complex matrix elements and dtype promotion

Complex constants in matrix_element=... expressions are supported directly. When a complex constant is present, the operator dtype is automatically promoted to a compatible complex dtype during build().

op = (
    SymbolicDiscreteJaxOperator(hi, "complex_branch")
    .for_each_site("i")
    .emit(shift("i", +1), matrix_element=1.0 + 0.5j)
    .build()
)

# op.dtype is complex-valued after promotion

Extending emission clauses

Emission methods are now first-class clause extension points, similar to iterators and predicates. Advanced users can register custom emission clauses by subclassing nkdsl.AbstractEmissionClause.

For a full extension walkthrough, see Extending DSL Emissions.