Skip to content

Lattice Maxwell and gauge link fields

Link variables on the cell complex of a periodic lattice, sampled or evolved in real time.

  • Name: lattice_gauge_fields
  • Field: physics/waves
  • Formalism: Monte Carlo sampling
  • References: Schwichtenberg 2020; Wilson 1974

Select this system

from skcomplex.systems import create_simulation, create_system, describe

system = create_system('lattice_gauge_fields')
entry = describe('lattice_gauge_fields')
trajectory = create_simulation('lattice_gauge_fields').prepare().run().trajectory_

Factory

@register_system(
    field='physics/waves',
    tags=('gauge', 'lattice', 'monte carlo', 'maxwell', 'cell complex'),
    references=('Schwichtenberg 2020', 'Wilson 1974'),
    defaults={'until': 5000, 'dt': 1},
    settings=_gauge_settings,
    observables=_gauge_observables,
)
def lattice_gauge_fields(
    size: int = 32,
    *,
    dimension: int = 2,
    n: int | None = None,
    beta: float = 2.0,
    dynamics: str = 'monte-carlo',
    charges: Sequence[float] | None = None,
    angles: Sequence[float] | None = None,
    amplitude: float = 0.1,
    seed: int = 0,
) -> System:
    """Return link variables on the cell complex of a periodic lattice, sampled or evolved in real time.

    With Monte Carlo dynamics, link angles sample the Wilson action `-beta sum_p cos(theta_p)` under discrete time, as
    U(1) angles or as the angles `2 pi k / n` of Z_n. With Hamiltonian dynamics, a potential on the links follows the
    lattice Maxwell equations `A_t = -E` and `E_t = codifferential(dA)` under continuous time, from static charges on
    the sites and a transverse wave. In two dimensions the U(1) mean plaquette at large size is `I_1(beta) / I_0(beta)`.

    Args:
        size:
            The number of sites along every axis.

        dimension:
            The number of axes of the lattice.

        n:
            The order of the Z_n group, or `None` for U(1).

        beta:
            The inverse coupling of the Wilson action.

        dynamics:
            `'monte-carlo'` or `'hamiltonian'`.

        charges:
            The static charge of every site, of total 0, or `None` for none, with Hamiltonian dynamics.

        angles:
            The initial link angles, or `None` for random angles, with Monte Carlo dynamics.

        amplitude:
            The amplitude of the initial transverse wave, with Hamiltonian dynamics.

        seed:
            The seed of the initial link angles.

    Returns:
        system:
            The system.

    Raises:
        ValidationError:
            The dynamics are unknown, or the charges do not hold one value per site of total 0.

    Examples:
        >>> from skcomplex.systems.physics.waves import lattice_gauge_fields
        >>> [element.label for element in lattice_gauge_fields(4).elements]
        ['links']
        >>> [element.label for element in lattice_gauge_fields(4, dynamics='hamiltonian').elements]
        ['links', 'charges']
    """
    if dynamics not in DYNAMICS:
        error_msg = f'Unknown dynamics {dynamics!r}. Use one of {", ".join(DYNAMICS)}.'
        raise ValidationError(error_msg)
    space = CellComplexSpace(LatticeSpace((size,) * dimension)).prepare()
    if dynamics == 'hamiltonian':
        return _maxwell_system(space, charges, amplitude)
    return _monte_carlo_system(space, n, beta, angles, seed)

Components

Elements:

  • GaugeLinkElement, from Element

Interactions:

  • WilsonSamplingInteraction, from SamplingInteraction
class GaugeLinkElement(Element):
    """Link of a lattice with an angle `theta`, the U(1) or Z_N variable of a lattice gauge theory.

    Args:
        label:
            The label of the link or the group on the links.

        visual:
            How the link is drawn, or `None` for `default_visual_`.

        theta:
            The angle of the link.

    Attributes:
        default_visual_:
            The visual of the link when it sets none.

    Examples:
        >>> from skcomplex.systems.physics.waves import GaugeLinkElement
        >>> GaugeLinkElement('link', theta=0.5).theta
        0.5
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        theta: Annotated[float, StateSpec(period=2 * pi)] = 0.0,
    ) -> None:
        super().__init__(label, visual=visual)
        self.theta = theta

class WilsonSamplingInteraction(SamplingInteraction):
    """Monte Carlo sampling of link variables with the local Wilson action of the plaquettes of a link.

    For link angles the action is `-beta sum_p cos(theta_p)`, where `theta_p` is the oriented sum of the link angles
    around the plaquette `p`. For the matrices of a group `SU(N)` it is `-(beta / N) sum_p Re tr U_p`, where `U_p` is
    the path-ordered product of the link matrices around `p`, and the move `'rotate'` multiplies a link by a random
    matrix of the group near the identity of spread `width`.

    Args:
        label:
            The label of the interaction, unique among the parts of its system.

        target:
            The path of the group on the edges of a cell complex.

        beta:
            The inverse coupling of the Wilson action.

        state:
            The name of the state that holds the link angles.

        move:
            `'rotate'` for U(1) or a matrix group, or `'random-value'` for Z_N.

        values:
            The angles a random-value move draws from.

        width:
            The largest change of a rotation.

        rule:
            The acceptance, `'metropolis'`, `'glauber'`, or `'heat-bath'`.

        schedule:
            `'colored'` or `'random-sequential'`.

        group:
            The matrix group of the links, or `None` for link angles.

        hits:
            The number of moves proposed per link and sweep of matrix links.

    Examples:
        >>> from skcomplex.systems.physics.common.fields import WilsonSamplingInteraction
        >>> WilsonSamplingInteraction('wilson', target='links', beta=2.0).beta
        2.0
        >>> from skcomplex.core.specs import MatrixGroupSpec
        >>> color = WilsonSamplingInteraction('wilson', target='links', state='U', group=MatrixGroupSpec('SU', 3))
        >>> color.objective.group.degree
        3
    """

    def __init__(
        self,
        label: str,
        *,
        target: Annotated[str, RoleSpec()],
        beta: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 2.0,
        state: str = 'theta',
        move: str = 'rotate',
        values: Sequence[float] = (),
        width: float = 1.5,
        rule: str = 'metropolis',
        schedule: str = 'colored',
        group: MatrixGroupSpec | None = None,
        hits: int = 1,
    ) -> None:
        super().__init__(
            label,
            target=target,
            state=state,
            objective=self._get_action if group is None else HolonomyScoreSpec(self._get_trace_action, group, hits),
            move=move,
            rule=rule,
            schedule=schedule,
            values=values,
            width=width,
        )
        self.beta = beta
        self.group = group
        self.hits = hits

    def _get_action(self, namespace: SimpleNamespace) -> Expression:
        """Return the terms of the Wilson action that hold the angle of a link."""
        theta = getattr(namespace.target, self.state)
        return -namespace.beta * neighbors(cos(exterior_derivative(theta)), over=CofaceNeighborhood())

    def _get_trace_action(self, holonomies: ComplexArray, beta: float) -> Array:
        """Return the Wilson action `-(beta / N) Re tr U_p` of the holonomies of the plaquettes."""
        degree = holonomies.shape[-1]
        return -beta / degree * np.trace(holonomies, axis1=-2, axis2=-1).real