qlat_utils.coordinate — 4-Component Coordinate Types for Lattice QCD¶
Source: qlat-utils/qlat_utils/coordinate.pyx
Note: Update this document when updating the source file.
Outline¶
Overview¶
The qlat_utils.coordinate module provides two 4-component coordinate types for
representing positions and extents on a 4-dimensional lattice:
Coordinate— integer coordinates (int32), used for lattice site positions, lattice sizes, and block dimensions.CoordinateD— double-precision coordinates (float64), used for continuous momenta, fractional positions, and interpolation points.
Both types support element-wise arithmetic, modular operations, serialization,
and iteration. The integer Coordinate additionally provides index↔coordinate
conversion for flat-array access and spatial volume computation.
import qlat_utils as q
total_site = q.Coordinate([8, 8, 8, 8])
site = q.Coordinate([3, 5, 2, 7])
mom = q.CoordinateD([1.0, 2.0, 3.0, 0.5])
Coordinate Class¶
Coordinate is a 4-component integer coordinate. Internally it wraps a
C++ array<Int, 4> where Int is int32_t. Components are indexed 0–3,
conventionally representing (x, y, z, t) or (μ=0,1,2,3).
Constructors¶
Coordinate()
Coordinate(x: list | tuple | np.ndarray | Coordinate)
Form |
Behavior |
|---|---|
|
Zero-initialize all components. |
|
From a list of exactly 4 integers. |
|
From a tuple of exactly 4 integers. |
|
From a shape-(4,) numpy array. |
|
Copy constructor from another |
import qlat_utils as q
c0 = q.Coordinate() # (0, 0, 0, 0)
c1 = q.Coordinate([3, 5, 2, 7]) # from list
c2 = q.Coordinate((8, 8, 8, 8)) # from tuple
c3 = q.Coordinate(c1) # copy of c1
Copying and Assignment¶
c.copy(is_copying_data=True) -> Coordinate
c @= other # in-place assignment
Method |
Description |
|---|---|
|
Return a copy. If |
|
Delegates to |
|
Delegates to |
|
|
c1 = q.Coordinate([1, 2, 3, 4])
c2 = c1.copy() # independent copy
c2[0] = 99
assert c1[0] == 1 # unaffected
c1 @= q.Coordinate([5, 6, 7, 8]) # in-place assignment
Serialization¶
Method |
Returns |
Description |
|---|---|---|
|
|
Components as a Python list. |
|
|
Components as a Python tuple. |
|
|
Components as a shape-(4,) |
|
|
Set components from list/tuple/ndarray of length 4. |
Coordinate also supports __getstate__ / __setstate__ for Python pickling,
and __repr__ for readable display.
c = q.Coordinate([3, 5, 2, 7])
assert c.to_list() == [3, 5, 2, 7]
assert c.to_tuple() == (3, 5, 2, 7)
assert np.array_equal(c.to_numpy(), np.array([3, 5, 2, 7], dtype=np.int32))
c.from_list([99, 88, 77, 66])
assert c.to_list() == [99, 88, 77, 66]
Norms and Volumes¶
Method |
Returns |
Description |
|---|---|---|
|
|
Sum of squares: |
|
|
Spatial distance squared: |
|
|
Product of all four components. |
|
|
Product of first three components (spatial only). |
lattice = q.Coordinate([8, 8, 8, 16])
assert lattice.sqr() == 8*8 + 8*8 + 8*8 + 16*16
assert lattice.r_sqr() == 8*8 + 8*8 + 8*8
assert lattice.volume() == 8 * 8 * 8 * 16
assert lattice.spatial_volume() == 8 * 8 * 8
Index Conversion¶
Map between 4D coordinates and 1D flat indices (row-major with component 0 fastest-varying):
c.from_index(index: int, size: Coordinate)
c.to_index(size: Coordinate) -> int
Method |
Description |
|---|---|
|
Set |
|
Return the flat index of |
size = q.Coordinate([4, 4, 4, 8])
c = q.Coordinate()
c.from_index(0, size)
assert c.to_list() == [0, 0, 0, 0]
c.from_index(1, size)
assert c.to_list() == [1, 0, 0, 0]
c.from_index(4, size)
assert c.to_list() == [0, 1, 0, 0]
# Round-trip
c = q.Coordinate([3, 2, 1, 5])
idx = c.to_index(size)
c2 = q.Coordinate()
c2.from_index(idx, size)
assert c == c2
Arithmetic¶
All arithmetic operators work element-wise on the four components.
Operator |
Description |
|---|---|
|
Element-wise addition. |
|
Element-wise subtraction. |
|
Unary negation. |
|
Unary plus (identity). |
|
Scalar multiplication ( |
|
Element-wise (Hadamard) product. |
|
Element-wise modulo. |
|
Element-wise integer division (floor). |
|
Element-wise scalar division (not exposed in Python). |
a = q.Coordinate([1, 2, 3, 4])
b = q.Coordinate([5, 6, 7, 8])
assert (a + b).to_list() == [6, 8, 10, 12]
assert (b - a).to_list() == [4, 4, 4, 4]
assert (-a).to_list() == [-1, -2, -3, -4]
assert (a * 3).to_list() == [3, 6, 9, 12]
assert (a * b).to_list() == [5, 12, 21, 32]
assert (b % a).to_list() == [0, 0, 1, 0]
assert (b // q.Coordinate([2, 2, 2, 2])).to_list() == [2, 3, 3, 4]
Indexing and Iteration¶
c[k] # get component k (0 ≤ k < 4)
c[k] = val # set component k
for x in c: # iterate over 4 components
c = q.Coordinate([3, 5, 2, 7])
assert c[0] == 3
assert c[3] == 7
c[2] = 99
assert c[2] == 99
vals = list(c)
assert vals == [3, 5, 99, 7]
Comparison¶
c1 == c2 # element-wise equality
Only == is supported. !=, <, >, etc. are not exposed in Python.
a = q.Coordinate([1, 2, 3, 4])
b = q.Coordinate([1, 2, 3, 4])
c = q.Coordinate([0, 0, 0, 0])
assert a == b
assert not (a == c)
CoordinateD Class¶
CoordinateD is the double-precision counterpart of Coordinate. It wraps a
C++ array<RealD, 4> where RealD is double. It shares the same serialization
API as Coordinate but uses float64 instead of int32 and has no
index-conversion or volume-computation methods.
Constructors¶
CoordinateD()
CoordinateD(x: list | tuple | np.ndarray | CoordinateD | Coordinate)
Form |
Behavior |
|---|---|
|
Zero-initialize all components. |
|
From a list of 4 numbers. |
|
Copy constructor from |
import qlat_utils as q
d0 = q.CoordinateD() # (0.0, 0.0, 0.0, 0.0)
d1 = q.CoordinateD([1.0, 2.0, 3.0, 0.5]) # from list
d2 = q.CoordinateD((4.0, 5.0, 6.0, 7.0)) # from tuple
d3 = q.CoordinateD(d1) # copy of d1
# Convert integer Coordinate to CoordinateD
c = q.Coordinate([3, 5, 2, 7])
d4 = q.CoordinateD(c) # (3.0, 5.0, 2.0, 7.0)
Serialization¶
Same API as Coordinate but returns float64 values:
d = q.CoordinateD([1.0, 2.0, 3.0, 0.5])
assert d.to_list() == [1.0, 2.0, 3.0, 0.5]
assert d.to_tuple() == (1.0, 2.0, 3.0, 0.5)
assert np.array_equal(d.to_numpy(), np.array([1.0, 2.0, 3.0, 0.5], dtype=np.float64))
d.from_list([99.0, 88.0, 77.0, 66.0])
assert d.to_list() == [99.0, 88.0, 77.0, 66.0]
Norm¶
Method |
Returns |
Description |
|---|---|---|
|
|
Sum of squares: |
CoordinateD does not have r_sqr(), volume(), or spatial_volume().
d = q.CoordinateD([3.0, 4.0, 0.0, 0.0])
assert abs(d.sqr() - 25.0) < 1e-15
Arithmetic¶
Operator |
Description |
|---|---|
|
Element-wise addition. |
|
Element-wise subtraction. |
|
Unary negation. |
|
Scalar multiplication ( |
|
Element-wise (Hadamard) product. |
|
True element-wise division ( |
|
Element-wise modulo. |
a = q.CoordinateD([1.0, 2.0, 3.0, 4.0])
b = q.CoordinateD([5.0, 6.0, 7.0, 8.0])
assert (a + b).to_list() == [6.0, 8.0, 10.0, 12.0]
assert (a * 0.5).to_list() == [0.5, 1.0, 1.5, 2.0]
assert (a / q.CoordinateD([2.0, 2.0, 2.0, 2.0])).to_list() == [0.5, 1.0, 1.5, 2.0]
Indexing and Comparison¶
Same as Coordinate: d[k], d[k] = val, for x in d, d1 == d2.
d = q.CoordinateD([1.0, 2.0, 3.0, 4.0])
d[0] = 9.0
assert d[0] == 9.0
assert d == q.CoordinateD([9.0, 2.0, 3.0, 4.0])
Module-Level Functions¶
Integer Functions¶
mod_coordinate(c, size) -> Coordinate¶
Wrap each component into [0, size[i]) via element-wise modulo. Equivalent to
c % size.
c = q.Coordinate([9, -3, 15, 5])
size = q.Coordinate([4, 4, 4, 8])
result = q.mod_coordinate(c, size)
assert result.to_list() == [1, 1, 3, 5]
smod_coordinate(c, size) -> Coordinate¶
Shortest-distance modulo: wrap each component into [-size[i]/2, size[i]/2).
c = q.Coordinate([3, 0, -2, 7])
size = q.Coordinate([4, 4, 4, 8])
result = q.smod_coordinate(c, size)
assert result.to_list() == [-1, 0, -2, -1]
smod_sym_coordinate(c, size) -> Coordinate¶
Symmetric smod: like smod but components equal to size[i]/2 become 0.
c = q.Coordinate([2, 2, 0, 4])
size = q.Coordinate([4, 4, 4, 8])
result = q.smod_sym_coordinate(c, size)
assert result.to_list() == [0, 0, 0, 0]
middle_mod_coordinate(x, y, size) -> Coordinate¶
Return the midpoint of two coordinates on a periodic lattice: wraps both into
[0, size), computes the shortest-distance midpoint, and wraps the result back
into [0, size).
size = q.Coordinate([8, 8, 8, 8])
a = q.Coordinate([1, 1, 1, 1])
b = q.Coordinate([5, 5, 5, 5])
mid = q.middle_mod_coordinate(a, b, size)
# Midpoint accounting for periodicity
coordinate_from_index(index, size) -> Coordinate¶
Convert a flat index to a Coordinate within bounds [0, size).
size = q.Coordinate([4, 4, 4, 8])
c = q.coordinate_from_index(7, size)
assert c.to_list() == [3, 1, 0, 0]
index_from_coordinate(x, size) -> int¶
Convert a Coordinate to a flat index. The coordinate can be negative; the
function applies mod(x, size) internally.
size = q.Coordinate([4, 4, 4, 8])
c = q.Coordinate([3, 1, 0, 0])
idx = q.index_from_coordinate(c, size)
assert idx == 7
assert q.coordinate_from_index(idx, size) == c
Double Functions¶
mod_coordinate_d(c, size) -> CoordinateD¶
Double-precision element-wise modulo. Equivalent to c % size.
c = q.CoordinateD([9.5, -1.0, 0.0, 5.0])
size = q.CoordinateD([4.0, 4.0, 4.0, 8.0])
result = q.mod_coordinate_d(c, size)
smod_coordinate_d(c, size) -> CoordinateD¶
Shortest-distance modulo for double coordinates.
c = q.CoordinateD([3.5, 0.0, -2.0, 7.0])
size = q.CoordinateD([4.0, 4.0, 4.0, 8.0])
result = q.smod_coordinate_d(c, size)
smod_sym_coordinate_d(c, size) -> CoordinateD¶
Symmetric smod for double coordinates.
c = q.CoordinateD([2.0, 2.0, 0.0, 4.0])
size = q.CoordinateD([4.0, 4.0, 4.0, 8.0])
result = q.smod_sym_coordinate_d(c, size)
middle_mod_coordinate_d(x, y, size) -> CoordinateD¶
Double-precision midpoint calculation on a periodic lattice.
size = q.CoordinateD([8.0, 8.0, 8.0, 8.0])
a = q.CoordinateD([1.0, 1.0, 1.0, 1.0])
b = q.CoordinateD([5.0, 5.0, 5.0, 5.0])
mid = q.middle_mod_coordinate_d(a, b, size)
Examples¶
Basic Usage¶
import qlat_utils as q
size = q.Coordinate([8, 8, 8, 16])
site = q.Coordinate([3, 5, 2, 7])
print(f"Lattice size: {size.to_list()}")
print(f"Site: {site}")
print(f"Volume: {size.volume()}")
print(f"Spatial volume: {size.spatial_volume()}")
Iterating Over a Lattice¶
import qlat_utils as q
size = q.Coordinate([4, 4, 4, 8])
for idx in range(size.volume()):
c = q.coordinate_from_index(idx, size)
assert q.index_from_coordinate(c, size) == idx
Coordinate Arithmetic¶
import qlat_utils as q
size = q.Coordinate([8, 8, 8, 8])
site = q.Coordinate([3, 5, 2, 7])
hop = q.Coordinate([1, 0, 0, 0]) # hop in +x direction
neighbor = site + hop
assert neighbor == q.Coordinate([4, 5, 2, 7])
opposite = -hop
assert opposite == q.Coordinate([-1, 0, 0, 0])
Modular Arithmetic on a Periodic Lattice¶
import qlat_utils as q
size = q.Coordinate([8, 8, 8, 8])
# Wrap a coordinate into fundamental domain
c = q.Coordinate([9, -3, 15, 7])
wrapped = q.mod_coordinate(c, size)
assert wrapped == q.Coordinate([1, 5, 7, 7])
# Shortest-distance displacement
disp = q.smod_coordinate(q.Coordinate([7, 0, 2, 3]), size)
assert disp == q.Coordinate([-1, 0, 2, 3])
Round-Trip Index Conversion¶
import qlat_utils as q
size = q.Coordinate([4, 4, 4, 8])
for i in [0, 1, 2, 3, 4, 7, 8, 15, 63, 64, 255, 511]:
c = q.coordinate_from_index(i, size)
assert q.index_from_coordinate(c, size) == i
Using CoordinateD for Momenta¶
import qlat_utils as q
size = q.Coordinate([8, 8, 8, 16])
mom = q.CoordinateD([1.0, 2.0, 3.0, 0.0])
mom_size = q.CoordinateD([8.0, 8.0, 8.0, 16.0])
# Scale momentum by 2π/L
phase = mom * (2.0 * 3.141592653589793)
phase = phase / mom_size
print(f"Momentum: {mom.to_list()}")
print(f"Phase: {phase.to_list()}")