Skip to content

Working with Causal Sets

This guide explains how to create and analyze causal sets using the pycauset.CausalSet class

Introduction

A causal set is a discrete structure consisting of a set of elements with a partial order relation that represents causality. In pycauset, causal sets are typically generated by "sprinkling" points randomly into a continuous spacetime manifold (like Minkowski space) and inducing the causal order from the manifold's lightcone structure.

Creating a Causal Set

The primary way to create a causal set is using the pycauset.CausalSet class.

import pycauset

# Create a causal set with 10,000 elements
# By default, this sprinkles into a 2D Minkowski Diamond
c = pycauset.CausalSet(10000)

Reproducibility

To ensure your causal set is identical every time you run your code, provide a seed. This can be an integer or a string.

# Using an integer seed
c1 = pycauset.CausalSet(10000, seed=12345)

# Using a string seed (useful for naming simulations)
c2 = pycauset.CausalSet(10000, seed="simulation_A_run_1")

Accessing the Causal Matrix

The core data of a causal set is its causal matrix. In pycauset, this is represented as a pycauset.TriangularBitMatrix for efficiency. You can access it via the .causal_matrix property or its alias .C.

# Get the causal matrix
C = c.causal_matrix

# Or using the alias
C = c.C

# C is a pycauset.TriangularBitMatrix
print(C)

Performance Note: The TriangularBitMatrix and DenseBitMatrix classes now use hardware-accelerated bit manipulation (AVX-512/NEON popcount). Operations like dot products, matrix multiplication, and transitive closure are approximately 30x faster than in previous versions.

Causal Structure

The matrix \(C\) is defined such that \(C_{ij} = 1\) if element \(i\) is in the causal past of element \(j\) (\(i \prec j\)), and \(0\) otherwise. Since the points are sorted by their time coordinate during generation, the matrix is strictly upper triangular.

What is a CausalSet Instance?

When you create an instance of pycauset.CausalSet, you might wonder what exactly is being stored in memory.

c = pycauset.CausalSet(1000)

The c object itself is extremely lightweight. It is essentially a metadata wrapper that holds: 1. N: The number of elements (e.g., 1000). 2. Seed: The random seed used for generation. 3. Spacetime: The definition of the manifold (e.g., "2D Minkowski Diamond"). 4. Handle to causal_matrix: A reference to the pycauset.TriangularBitMatrix object.

What is NOT stored: * Coordinates: The coordinates of the 1000 points are not stored in the c object. They were generated temporarily to compute the matrix and then discarded. * Full Matrix in RAM: The causal matrix is backed by a file on disk. It is not fully loaded into RAM unless you explicitly read all of it.

The "End Product" of the initialization is the Causal Matrix stored on disk. The pycauset.CausalSet instance is just your handle to access that matrix and remember how it was created.

Large Scale Simulations

pycauset is designed for large-scale simulations. The pycauset.CausalSet class uses a stateless sprinkling technique (see Stateless Sprinkling) that avoids storing the coordinates of the points. This means you can generate causal sets with billions of elements without running out of RAM, provided you have enough disk space to store the resulting bit matrix.

# Generating a very large causal set (e.g., 1 million elements)
# This is memory-safe!
c_large = pycauset.CausalSet(1_000_000)

# The matrix is stored on disk, mapped into memory only as needed
C_large = c_large.C

Spacetimes

You can sprinkle into different spacetime manifolds using the spacetime parameter. The pycauset.spacetime module provides standard manifolds.

Minkowski Diamond

The default spacetime is a 2D Minkowski Diamond (Alexandrov interval).

import pycauset
from pycauset import spacetime

# Explicitly specifying the diamond
diamond = spacetime.MinkowskiDiamond(dimension=2)
c = pycauset.CausalSet(n=1000, spacetime=diamond)

Minkowski Cylinder

A flat spacetime with periodic spatial boundary conditions (\(S^1 \times \mathbb{R}\)).

# A cylinder with height 2.0 and circumference 5.0
cyl = spacetime.MinkowskiCylinder(dimension=2, height=2.0, circumference=5.0)
c = pycauset.CausalSet(n=1000, spacetime=cyl)

Sprinkling Modes

Fixed N

Specify n to generate exactly that many elements.

c = pycauset.CausalSet(n=1000)

Fixed Density

Specify density (\(\rho\)) to generate elements based on a Poisson process. The actual number of elements \(N\) will vary according to the Poisson distribution \(N \sim \text{Poisson}(\rho V)\).

# Sprinkle with density 100.0
# If volume is 1.0, expected N is 100
c = pycauset.CausalSet(density=100.0)
print(f"Realized N: {c.N}")
print(f"Realized Density: {c.rho}")

Saving and Loading

You can save a CausalSet to a portable .pycauset file. This single-file container contains the metadata (parameters, seed, spacetime info) and the binary causal matrix.

# Save
c.save("my_simulation.pycauset")

# Load
# This reconstructs the object exactly without re-sprinkling
c_loaded = pycauset.CausalSet.load("my_simulation.pycauset")

Adding Matter (Fields)

Once you have a causal set, you can define quantum fields on it to study particle propagation and entanglement. PyCauset separates the geometry (the set) from the matter (the field).

See the Field Theory guide for details on how to define Scalar Fields and compute propagators.

from pycauset.field import ScalarField

# Define a field on the set
field = ScalarField(c, mass=1.0)
K = field.propagator()