The core language

Qlua keeps Lua 5.1 as it is, with three replacements, two extensions, and one library rewritten. Everything the Lua 5.1 reference manual describes and that is not listed below — assert, pairs, pcall, setmetatable, string.*, table.*, math.*, coroutine.*, debug.* and the rest — is present and behaves as it does in stock Lua, and is documented there rather than here.

Replaced globals

type

type(x)                                           --> string

Like Lua's type, except that a qlua object reports its own kind rather than "userdata".

GroupNames
scalars"complex", "gamma"
dense arrays"vector.int", "vector.real", "vector.complex", "matrix.real", "matrix.complex"
single-site"color.vector", "color.matrix", "dirac.fermion", "dirac.propagator"
the lattice"lattice", "subset", "multiset"
lattice fields"lattice.int", "lattice.real", "lattice.complex", "lattice.color.vector", "lattice.color.matrix", "lattice.dirac.fermion", "lattice.dirac.propagator"
random states"random.state", "lattice.random.state"
communication"scatter", "gather"
readers and writers"qio.reader", "qio.writer", "aff.reader", "aff.writer", "hdf5.reader", "hdf5.writer", "file"
solvers"clover", "twisted", "mdwf", "qop.WilsonMG"
other"latmat", "contract.state"

Anything else, including a plain Lua value, gets Lua's own answer.

A deflator is the exception that is easy to trip over: it is a Lua table carrying a metatable, not a userdata, so type(df) is "table" and not "clover.deflator". Those names exist inside qlua, where they appear in error messages, but type never produces them. Test a deflator by what it answers to, not by its type.

A number of colors is not part of the name: a ColorVector over two colors and one over three both report "color.vector".

The twisted, scatter, gather, latmat, contraction-state and file names arrived after the 2026.10d tag; before that type() answered "userdata" for all six.

print

print(...)                                        --> nothing

As Lua's, but each line is prefixed with [rank]: when the job has more than one rank, and the whole line is written with one printf, so lines from different ranks do not interleave mid-line.

getmetatable

getmetatable(x)

For a table, Lua's. For a qlua object it returns the metatable's __metatable string rather than the table itself, so a script cannot reach in and rewrite a type's methods.

Added globals

complex and gamma are constructors, described under Complex numbers and The Dirac algebra. qcd, vector, matrix, gsl, openmp, xml, scripts and _rcParam each have a section of their own.

io

The whole io library is replaced. What is there is a small, parallel-aware subset: there is no io.read, no io.input/io.output, and no popen.

io.open

io.open(name, mode)                               --> file

mode is passed to fopen. A read mode ("r", "rb", "rt") opens the file on every rank, and the call fails unless every rank succeeded. Any other mode opens the file on the master node alone; the other ranks get a dummy that accepts writes and discards them. Raises on failure.

io.lines

io.lines(name)                                    --> iterator

Opens name for reading and returns an iterator over its lines, without the newline. The file is closed when the iterator runs out.

io.fexists

io.fexists(name)                                  --> boolean

True when name exists and is a regular file. The master node decides and broadcasts, so every rank gets the same answer.

io.dexists

io.dexists(name)                                  --> boolean

As io.fexists, for directories.

io.stdout

The standard output, as a file object. Writes go through the master node.

io.stderr

The standard error, as a file object.

file:write

f:write(string)                                   --> nothing

Writes the string. Only the master node's write reaches the disk; the result is agreed across ranks and raises everywhere if it failed.

file:lines

f:lines()                                         --> iterator

An iterator over the remaining lines. Unlike io.lines, it does not close the file at the end.

file:flush

f:flush()                                         --> nothing

file:close

f:close()                                         --> nothing

Closing io.stdout or io.stderr flushes them instead.

os

The standard os keeps clock, date, difftime, execute, getenv, remove, rename, setlocale and tmpname, and gains the following.

os.exit

os.exit([code])                                   --> does not return

Shuts QDP down cleanly first, so the job ends rather than hanging in a collective. Always use this rather than letting a rank fall off the end on its own.

os.time

os.time()                                         --> number

Wall-clock seconds as a double, with microsecond resolution, taken on the master node and broadcast, so every rank reads the same instant. This replaces Lua's os.time and takes no table argument.

os.nodetime

os.nodetime()                                     --> number

The same clock read locally, without the broadcast. Ranks will disagree; that is the point, for measuring per-rank cost.

os.ctime

os.ctime(t)                                       --> string

Formats a time from os.time as a 24-character date string.

os.random

os.random()                                       --> number

A fresh 32-bit unsigned integer from /dev/urandom. Present only when that device could be opened at startup. Each rank gets its own value: broadcast it if the job must agree, which it must for anything that seeds a lattice random state.

os.node

os.node()                                         --> number

The calling rank's number, counted from 0. The same value as qcd.node() and L:node().

os.sleep

os.sleep(seconds)                                 --> number

Sleeps; returns the number of seconds left unslept if a signal cut it short.

os.limit

os.limit(name)                                    --> soft, hard
os.limit(name, kbytes)                            --> nothing
os.limit(name, soft, hard)                        --> nothing

Reads or sets a resource limit, in kilobytes. name is "as", "data", "rss" or "stack".

os.rm

os.rm(name [, {all=false, wait=true, verbose=false, nofail=false}])

Removes one file or one empty directory. By default only the master node does the removing, and every rank waits at a barrier afterwards; all=true has every rank remove its own copy, which is what a per-rank scratch file needs. With nofail=true a failure returns the strerror text instead of raising.

os.mkdir

os.mkdir(name [, {mode=0777, all=false, wait=true}])

Creates one directory. An existing directory is not an error. mode is the permission bits. all and wait mean exactly what they mean for os.rm: with all=false, the default, only the master node creates the directory; with all=true every rank creates its own, which is what a per-rank scratch directory needs. With wait=true, the default, every rank waits at a barrier before the call returns, so the directory is known to exist everywhere afterwards.

os.mkdir_path

os.mkdir_path(path [, {mode=0777, all=false, wait=true}])

As os.mkdir, including the meaning of mode, all and wait, but it creates every missing component of path rather than only the last.

os.set_trace

os.set_trace([seconds])

Spins in a sleep loop until a debugger clears the qlua_set_trace flag. A hook for attaching to a running rank; it never returns on its own.

package

package.path is set at startup to

./?.qlua;<libdir>/?.qlua;<libdir>/lhpc/?.qlua;./qlib/?.qlua

unless QLUALIB is set in the environment, which replaces it outright.