VIRIAN
desk[at]virian.com
code
|
text
Parabellum
January 1, 2024
687
In the spirit of Galileo’s empiricism—which has been described as “the last
resort of the failed mathematician”—we present Parabellum
[1]
, a program for
simulating and quantifying the outcomes of military engagements. As mathe
matical fundamentalists scribble away, attempting to find increasingly refined
analytical solutions to the sub-problems of strategy, Parabellum already now
addresses two of reality’s most persistent and pernicious shortcomings: a)
single-threadedness, and b) ambiguity. With Parabellum, we (the authors,
funded by the Swiss Federal Department of Defence) address both through
parallelization.
Setting multiple digital twins
[2]
of the battlefield—each with their slight
variations in initial conditions—in concurrent motion, the Parabellum operator
might compute statistics over the various trajectories, so as to estimate the
truth and importance of any proposition. Indeed, it has been said that “facts
speak for themselves with overwhelming precision”
[3]
, but, without Parabel
lum, this is only exactly two thirds true:
1)
facts do speak for themselves,
2)
with precision, but
3)
rarely overwhelmingly so. As in the case of a subtly unfair
die where one might gauge the true distribution of outcomes by recording
multiple rolls thereof.
ĐIỆN BIÊN PHỦ
As an anecdote on the dangers of ambiguity, take the French military disaster
(or perhaps rather the Viet Minh military success) that was the fifty-six day
siege known as the Battle of Điện Biên Phủ. It was preceded by a world soaked
in facts, all speaking for themselves, but in subtle ways—not with the ferocity
that posterity since brought them. The French had built their fortress on the
red earth of the Phủ valley, encircled by a jungle pregnant with subtle facts
of the Viet Minh. The French named their outposts after women; Beatrice,
Gabrielle, Dominique—this one: Céline. The Viet Minh came in the night and the
rain, ghosts in sandals, hauling artillery up slopes where no European gunner
would think a gun could go. In the night, the French watched the dark green
hills erupt in fire. As the days and weeks progressed, the French reinforcements
would continue, their birds of steel containing reports and gliding above a
terrain within both where embedded the same message: “to land here is to
die”. Indeed, the airstrip would become a graveyard of various French Dakota
transporters. The night sky made starless with shrapnel and tracer, parachutes
blooming in the night—some men landed alive, some did not. The wounded call
out in French, in Vietnamese, and in the guttural language of the dying. On May
7, 1954, the last French radio message crackled out: “L’ennemi est partout. La
situation est très grave”
[4]
.
THE GARDEN OF FORKING PATHS
How is one then to reason probabilistically about future—potential or eventual
—outcomes under such ambiguous circumstances? From an information theo
retical point of view, where does one locate the French error at Céline?
Parabellum, viewed in a vacuum, is thus a potentially parallelizable world
awaiting that which acts. Appendix A shows an example of single and paralel
trajectories. Recalling that counting is the bedrock of probability
[5]
, Parabel
lum proposes the following procedure:
1.
Create
𝑛
simplified facsimiles of the reality about which one wishes to reason
2.
Set these in concurrent motion, recording
𝑡
𝑖
=
{
(
𝑠
0
,
𝑎
0
)
,
…
,
(
𝑠
𝑚
,
𝑎
𝑚
)
}
3.
Compute statistics over
{
𝑡
1
,
…
,
𝑡
𝑛
}
to divine the value of strategy
𝜋
(
𝑠
)
→
𝑎
Each process can be thought of as consisting of a world (yielding states
𝑠
) and
that which operates within it (yielding actions
𝑎
).
A | CODE
from jax import random, vmap, lax
import parabellum as pb
rng, key = random.split(random.PRNG(0))
env, scene = pb.env.init_fn({"place": "Điên Biên Phù"})
Load in jax programs and parabellum, and declare global varaibles
def action_fn(rng):
coord = random.normal(rng, (env.num_units, 2))
shoot = random.bernoulli(rng, 0.5, shape=(env.num_units,))
return pb.types.Action(coord=coord, shoot=shoot)
Function for taking random action
def step_fn(state, rng):
action = action_fn(rng)
obs, state = env.step(rng, scene, state, action)
return state, (state, action)
Function for taking steps in a scan.
rngs = random.split(rng, (n_steps, n_sims))
Random numbers for simualtions, and parallel simulations
obs, state = env.reset(rngs[0][0], scene)
state, seq = lax.scan(step, state, rngs[0])
Running
𝑛
trajectories in parallel, we merely use
vmap
:
obs, state = vmap(env.reset, in_axes=(0, None))(rngs[0], scene)
state, seq = lax.scan(vmap(step), state, rngs)
REFERENCES
[1]
T. Anne
et al.
, “Harnessing Language for Coordination: A Framework and
Benchmark for LLM-Driven Multi-Agent Control,”
IEEE Transactions on
Games
, pp. 1–25, 2025, doi:
10.1109/TG.2025.3564042
.
[2]
U.S. Department of Defense, Office of the Deputy Assistant Secretary of
Defense for Systems Engineering, “Digital Engineering Strategy,” Wash
ington, DC, Jun. 2018.
[3]
J. Conrad,
Typhoon
. United Kingdom: Pall Mall Magazine, 1902.
[4]
P. W. Shull, “The Battle of Dien Bien Phu: Strategic, Operational and Tac
tical Failure:,” Fort Belvoir, VA, Apr. 1999. doi:
10.21236/ADA363910
.
[5]
R. L. Schilling,
Measures, Integrals and Martingales
, 2nd ed. Cambridge:
Cambridge university press, 2017.