In fantasy movies and medieval displays, we see chainmail as that distinctive mesh of linked metal rings. It’s hard to imagine how something so simple, made of nothing but linked metal rings, protects the human body in combat. But it worked well enough that people wore it for centuries. What once served as flexible protective clothing has now resurfaced as a subject of interest in computational design, wearable technology, and metamaterials. In this computational essay, I model four types of chain mail patterns, the classic European 4-in-1, the dense Japanese 6-in-1, a 4-in-1 square weave, and a modern structure based on octahedral, using Wolfram Language. Each weave is constructed as a 3D geometric fabric, paying close attention to how rings interlock, rotate and repeat across space. Finally, to further explore how chainmail responds to mechanical displacement, I used Wolfram’s differential equation solvers to simulate deformation in the octahedral weave.

Introduction

Chainmail has existed in many forms throughout history. It was most famously used as armor in medieval Europe, where the European 4-in-1 pattern became the standard. This weave struck a balance between protection and mobility which made it practical for battle. In Japan, a different approach emerged. The Japanese 6-in-1 weave, used in samurai armor and even in decorative textiles, created a denser surface with a distinct hexagonal layout. Other variants evolved more recently, especially in modern applications where chain mail is used for architectural meshes, aerospace components, or experimental materials. One modern twist comes from designers and engineers who began exploring chain mail as structure rather than just fabric. I was drawn to this idea and created a custom octahedral-based pattern inspired by spatial trusses. I also explored a more geometric, grid-aligned 4-in-1 variation with using squares right-angle symmetry. These four weaves (two historic and two experimental) became the foundation for my project.

Decoding Chainmail patterns using 3D Euclidean Geometry

Part 1: European 4-in-1

This weave is created by circular rings interlocked in a way where each centre jump ring (the connector) is interlocked with 4 outer rings. I achieved this design by producing a front and back layer, which is what allows for the interlocking to appear in the first place. Structurally, the European 4-in-1 consists of rows of offset rings, arranged so each ring lies smoothly between neighboring rows, forming a compact and symmetrical pattern.
Instead of drawing rings at fixed positions, I decided to separate the shape from the location. This way I could define a ring’s geometry once, then just shift those points to wherever I needed the ring to appear. The function takes a set of control points that define the ring shape and adds a position vector to move the entire ring:
In[]:=
makeEuropeanRing[radiusPoints_,pos_]:=​​radiusPoints+pos
This separation turned out to be useful for everything that followed. I could focus on the complex positioning logic without constantly reshaping individual rings.
The front layer arranges rings in a regular grid, but I needed to solve the centering problem first. Without proper offset calculations, the grid would always anchor to one corner rather than centering itself around the origin.
In[]:=
makeFrontRingGrid[rowCount_,columnCount_,basePoints_,spacingX_,spacingY_]:=​​Module[{offsetX,offsetY,totalRings},​​totalRings=Length[basePoints];​​offsetX=spacingX*(rowCount-1)/2;​​offsetY=spacingY*(columnCount-1)/2;​​Table[​​Table[​​makeEuropeanRing[basePoints[[n]],{i*spacingX-offsetX,j*spacingY-offsetY,0}],​​{n,totalRings}],​​{i,0,rowCount-1},{j,0,columnCount-1}]​​]
Here’s where the real geometry began. The back layer actually couldn’t just be a copy of the front. Each ring needs to sit diagonally offset to fall into the gaps between front rings, and it needs to appear to pass through the front layer rather than float above it. The diagonal offset was the first piece. In European 4-in-1, the back rings sit exactly halfway between the front rings in both X and Y directions. So if front rings are spaced at intervals of spacingX and spacingY, the back rings need to shift by
spacingX
2
and
spacingY
2
.
The Z-flip was less obvious but equally important. Simply placing rings at the same Z-coordinate would make them appear to sit alongside the front rings. To create the interlocking illusion, I needed the back rings to appear behind the front rings from some angles and in front from others. Flipping the Z-coordinate does this by inverting the ring’s depth profile:
In[]:=
makeBackRingGrid[frontGrid_,spacingX_,spacingY_]:=​​Map[​​point|->{point[[1]]+spacingX/2,​​point[[2]]+spacingY/2,​​-point[[3]]},​​frontGrid,{3}​​]
Converting these point arrays into something that looks like actual metal rings required handling the 3D visualization carefully. I needed to turn each set of control points into a smooth closed curve and then give those curves realistic thickness.
BSplineCurve handles the smoothing. It interpolates between my control points to create natural-looking ring shapes. The SplineClosed → True parameter makes each ring form a complete loop, while SplineDegree → 2 keeps the curves smooth without being overly complex. Tube then wraps each curve with the specified thickness to give it volume:
In[]:=
renderEuropeanWeave[frontGrid_,backGrid_,ringThickness_]:=​​Graphics3D[​​{​​Specularity[White,100],​​Table[​​Tube[​​BSplineCurve[frontGrid[[i,j]],SplineClosed->True,SplineDegree->2],ringThickness],​​{i,Length[frontGrid]},{j,Length[frontGrid[[1]]]}],​​Table[​​Tube[​​BSplineCurve[backGrid[[i,j]],SplineClosed->True,SplineDegree->2],ringThickness],{i,Length[backGrid]},{j,Length[backGrid[[1]]]}]​​},​​Lighting->"Dark",​​ViewAngle->Pi/25,​​Boxed->False,​​ImageSize->Large,​​PlotRange->All​​]
The main function ties everything together, handling the parameter setup and calling each component in the right sequence. The base ring shape is defined by eight control points that I fine-tuned until the rings looked natural when interlocked. The scaling factor of (2/3) came from testing. It gives rings that are substantial enough to look realistic but not so large that they overwhelm the interlocking pattern:
In[]:=
europeanFourInOne[rowCount_,columnCount_]:=​​Module[​​{baseRingPoints,ringSpacingX=4.5,ringSpacingY=4,ringThickness=0.2,frontGrid,backGrid},baseRingPoints={{2.12,1.83,1.06},{3,0,0},{2.12,-1.83,-1.06},{0,-2.59,-1.5},{-2.12,-1.83,-1.06},{-3,0,0},{-2.12,1.83,1.06},{0,2.59,1.5}}*(2/3);​​frontGrid=makeFrontRingGrid[rowCount,columnCount,baseRingPoints,ringSpacingX,ringSpacingY];​​backGrid=makeBackRingGrid[frontGrid,ringSpacingX,ringSpacingY];​​renderEuropeanWeave[frontGrid,backGrid,ringThickness]​​]
In[]:=
europeanFourInOne[5,5]
Out[]=

Part 2: Square 4-in-1

Unlike the European version, the square 4-in-1 weave emphasizes right-angle geometry. Each ring is still interlocked with four others, but the grid it follows is rectangular and orthogonal which gives it a more rigid and uniform appearance.
The first step is defining the ring shape. These coordinates are hand-tuned to reflect symmetry and crisp square alignment. I based this on a Wolfram Demonstrations project which was critical to preserving the blocky quality of this weave:
In[]:=
makeSquareRingPoints[]:={​​{-2,-1.73,-1},{-1,-1.73,-1},{0,-1.73,-1},{1,-1.73,-1},{2,-1.73,-1},{2,-0.86,-0.5},{2,0,0},{2,0.86,0.5},{2,1.73,1},{1,1.73,1},{0,1.73,1},{-1,1.73,1},{-2,1.73,1},{-2,0.86,0.5},{-2,0,0},{-2,-0.86,-0.5}​​}
Similar to our previous kind of Chainmail, this positions all the rings in space and builds both the front and back layers of the grid. Each ring is spaced evenly, then the back layer is generated by shifting and vertically flipping the front layer to ensure proper interlocking across the Z-axis:
In[]:=
generateRingGridsSquare[rowCount_,columnCount_,spacingX_,spacingY_]:=Module[{baseRingPoints,totalRings,offsetX,offsetY,front,back},​​baseRingPoints=makeSquareRingPoints[];​​totalRings=Length[baseRingPoints];​​offsetX=spacingX*(rowCount-1)/2;​​offsetY=spacingY*(columnCount-1)/2;​​front=Table[​​Table[​​baseRingPoints[[n]]+{i*spacingX-offsetX,j*spacingY-offsetY,0},{n,totalRings}],{i,0,rowCount-1},{j,0,columnCount-1}];​​back=Map[​​point|->{​​point[[1]]+spacingX/2,​​point[[2]]+spacingY/2,​​-point[[3]]​​},​​front,{3}​​];​​{front,back}​​]
The offset and transformation logic works the same as before, but now it operates on the angular square ring geometry instead of smooth curves.
Our final step is to tie everything together. This function defines spacing, initializes the viewpoint, generates the front and back layers using the grid function, and then renders the structure using smooth closed B-splines. The result is a clean chainmail fabric with perfect symmetry in all directions:

Part 3: Hybrid Octahedral

Of the four weave types I worked on, the hybrid octahedral Chainmail was the most geometrically demanding. Arranging the octahedra across a grid with consistent orientation and interlocking symmetry proved tricky due to the presence of eight triangular faces. What finally solved the problem was correct rotation: a 45° twist around both the x and y axes, applied in an alternating sequence across the rows and columns. I found that that subtle adjustment was enough to let the structure breathe and bond.
To begin, just like I did with the others, I defined a function that builds a single shape (in this case- an octahedron) using cylinders between its vertices. The rotation logic is embedded in this part as it checks whether the grid position is even or odd and rotates accordingly. This alternating pattern prevents uniform stacking and creates the offset needed for proper interlocking for however many rows/columns. The RotationMatrix functions create the actual transformation matrices, and I combine them by matrix multiplication. This gives each octahedron a unique orientation based on its grid position. The cylinder generation happens after rotation. I take each pair of vertices defined in trussEdges and create cylinders between them with a small radius. The # symbol represents each vertex as it gets transformed by the rotation matrix and shifted by the center position:
The full weave is built by placing one octahedron at a time across a grid. But the catch is that not every cell gets one. To create the hybrid checkerboard pattern, I skip any location where both row and column indices are even. This checkerboard approach solves a fundamental geometry problem. If I tried to place octahedra at every grid position, they would interfere with each other. The alternating pattern creates natural gaps where the structures can interlock:
At this point, all the geometry is defined. I choose a grid size and spacing that gives the octahedra enough room to rotate and extend without crashing into their neighbors:

Part 4: Japanese 6-in-1

While the European weaves relied on two interlocked layers, the Japanese 6-in-1 structure builds its pattern from a single grid. Each large ring in the weave is surrounded by six smaller rings (three above and three below) forming a flower-like tessellation when viewed from the top. The biggest hurdle I faced here was how to position and orient different types of rings so they would interlock without actually intersecting. Creating one layer wasn’t enough as diagonal connectors had to be added on alternating rows, and you guessed it! Precise rotations. This meant building the weave component by component: horizontal rows, vertical columns, then diagonals.
The first step was to create an individual torus ring at a given position, with control over its orientation and size. This function creates a torus at the origin, then applies two transformations in sequence. The rotation happens first (rotating the torus 90 degrees around the specified axis), then the translation moves it to the final position. The Composition ensures these transformations apply in the right order:
With that in place, the next move was to build a full horizontal row of rings. Each ring had to be evenly spaced and remain flat in the XY plane for which I rotated the torus 90 degrees in the Z axis which kept them flat and horizontal:
Once rows were working, the vertical columns were next. These rings had to rotate to stand up and fit between adjacent rows, offset by half a unit to ensure clean intersections. The {1, 0, 0} rotation axis makes the rings stand vertically, creating the perpendicular connections between horizontal rows.:
For diagonal rings, they needed to be rotated in the XY plane, placed between main grid rings, and carefully angled so they wouldn’t clip through their neighbors. This function creates a vertical torus first, then applies both translation and rotation. The rotation around the Z axis tilts the ring in the XY plane by the specified angle. The angle parameter became crucial for preventing intersections:
I needed full rows of diagonals, tilted one way or the other depending on whether the row was odd. The critical insight was using the Mean of two positions to find the exact center point where the tilted connector ring needs to land. Without this averaging, the diagonals would float off-grid or overlap the wrong rings:
The main function assembles the full Japanese 6-in-1 pattern. It loops through each row and checks whether the row index is odd or even. This matters because the Japanese 6-in-1 pattern alternates its structure row by row. For each row, it places a horizontal row of rings, vertical column connectors and two sets of diagonal rings (one angled 60 degrees left, one angled 60 degrees right), but only if it’s not the last row so that there are no disjointed rings left :
​
The final layout came together by tuning just a few key variables, the spacing, ring sizes and diagonal angles so the entire weave could be scaled or adjusted easily. The spacing controls how far apart the rings sit on the grid, while r1 and r2 set the major and minor radii of each torus. With everything defined in terms of variables, the structure stays clean, adjustable, and reproducible.

Machine Learning Classification

After building all four chainmail types, I was curious whether a computer could learn to recognize them based on visual patterns alone. To test this, I generated a dataset of images for each weave and started with unsupervised learning. Using FeatureSpacePlot, I explored how the images clustered without labels. Then, I moved on to supervised learning by training a classifier with Classify to see if the model could correctly identify the weave type from unseen images.

Generating Images

To train any model, the first requirement is a reliable dataset. But for something like chainmail (which doesn’t have preexisting labeled image sets) I had to create my own from scratch. This function generates a clean 3D rendering of a square 4-in-1 chainmail structure using adjustable parameters for ring thickness, spacing, camera angle, and lighting. These variables gave me the flexibility to simulate different viewpoints and subtle structural changes without ever modifying the weave itself:
Rather than using fixed values, I randomized each rendering by sampling from a range of possible inputs. This included the number of rows and columns, the ring thickness, and even the perspective of the virtual camera and therefore the rotation angle. Each time the function is called, it returns a fresh image that still clearly shows the pattern but with enough variety to teach the model about non-essential differences:
Here I used that function to produce 50 images of the square 4-in-1 weave:
I moved on to the European 4-in-1 pattern with a similar approach. Unlike the square grid, this weave involves diagonally offset rows, where each ring overlaps with four neighbors in a diamond configuration:
To reflect how this weave might appear under different viewing conditions, I randomized ring spacing in two directions (X and Y) along with the number of rows and columns. Each image still preserved the underlying structure but introduced subtle distortions, helping the model later distinguish between essential and incidental features:
I produced 50 distinct renderings of the European 4-in-1 weave:
The same logic for generating images was used in the two examples below, for the Japanese 6-in-1 as well as the Hybrid Octahedral weave:
The complexity of this weave could help or hurt classification. More visual detail might make the patterns easier to distinguish, but the density could also make it harder for the model to spot the key geometric relationships. Either way, it creates a good test of whether the classifier can handle visual complexity.
Finally, the octahedral chainmail images:
Unlike the ring-based patterns, the octahedral images show sharp geometric wireframes with clear angular structures. This makes them visually distinct from all the other chainmail types. The checkerboard placement and rotation variations create patterns that look more like crystalline lattices than traditional chainmail.
Now that I have all the images generated, I created a straightforward master function for easier extraction of data:
This function acts as a dispatcher that calls the appropriate image generation function based on the chainmail type. It standardizes the interface so I can generate datasets for any pattern without remembering the specific function names or parameter requirements.

Unsupervised Learning

Stephen Wolfram, in his book “A New Kind of Science”, famously categorized cellular automata into four types. He recently, in a blog post, “Can AI Solve Science?”, he revisited this classification using modern tools- showing how a simple FeatureSpacePlot can visually distinguish these types without any prior labeling or training. Inspired by this, I wondered if something similar might work for my project. So I turned to Wolfram’s built-in FeatureSpacePlot function to see whether the four different chainmail weaves I modeled would naturally separate in feature space without labeling and training.
FeatureSpacePlot automatically extracts visual features from images and projects them into a reduced dimensional space where similar images cluster together. Just like Wolfram’s cellular automata revealed unexpected organizational patterns, the chainmail images formed distinct clusters in feature space. The resulting plot shows clear clustering patterns where each chainmail type groups together. The octahedral pattern (with its angular wireframes) forms the most distinct cluster, well-separated from the ring-based patterns. The European, Japanese, and square patterns form their own clusters but with some overlap, suggesting these ring-based structures share visual similarities while still maintaining distinguishable characteristics. This unsupervised analysis confirms that the visual differences between chainmail types are strong enough for automatic detection. The natural clustering suggests that supervised classification should work well since the feature extraction is already finding meaningful distinctions between the patterns.

Supervised Learning

With the unsupervised analysis showing some distinction, I moved on to training a supervised classifier. I generated a larger dataset of 300 images per chainmail type and split them into training and testing sets using an association:
The Wolfram Language Classify function automatically handles the machine learning pipeline, from feature extraction to model training. It chose logistic regression as the classification method and trained on 1000 total examples (250 per chainmail type).
Testing the classifier on new data revealed interesting results. The model achieved approximately 97-98% accuracy on test examples, which is excellent but shows where the classification challenges actually lie:
The classifier reached 98.5% accuracy, far above the 25% baseline for random guessing. Most mistakes happened between the square and European 4-in-1 patterns, which look visually similar due to their grid-like structure. This confusion is understandable, especially when the square pattern is viewed at angles where its orthogonal layout is less obvious. In contrast, the Japanese 6-in-1 and octahedral weaves were almost always identified correctly. As expected, their unique geometry and density made them visually distinct, allowing the model to classify them with confidence. The high probability scores and low cross entropy confirm that the predictions were both accurate and reliable.

Lifting the Hybrid Octahedral Structure

After reading about this structure’s unique mechanical and materialistic properties, I was curious how it would react to being lifted up from a certain point. To do this, I utilized the SolidMechanicsPDE Component on a cuboid, and then transferred the results to my figure as the function does not support 3D materials with rotations and gaps.
We start with recreating our Octahedral Structure from earlier by calling the function:
The material properties were chosen carefully to make the simulation effective and easy to interpret. I set the Young’s modulus to 1000 Pa, which is quite low. This was intentional, as the goal was not to show deformation, but to show how the chainmail moves when, for example, it is picked up by a corner. The Poisson ratio was set to 0.35, a standard value for metals. This means that when the material stretches in one direction, it contracts by 35 percent in the other direction.
The simulation applies a lifting force in the z-direction at the maximum y-value, while keeping y-values in the bottom half fixed:
Now, I apply the same concept to my Chainmail structure. The displacement field from the finite element analysis gets interpolated and applied to each octahedron center:
The displacement calculation shows how each octahedron moves based on the underlying deformation field. The color-coded visualization below reveals the displacement magnitude across the structure, with the highest displacements (shown in orange) occurring where the lifting force is applied:
The center position mapping handles the complexity of the checkerboard pattern. Since the octahedral structure only exists at certain grid positions (skipping even/even locations), the code maps between the actual positions in the centers array and the logical grid coordinates. For example, the {2,2} position on the cuboid is actually {2,3} on the lattice, the {2,3} position on the cuboid is actually {2,5} on the lattice and so on :
The displacedOctas table rebuilds each octahedron at its new displaced position while maintaining the proper rotation characteristics. The If[EvenQ[pos[[1]]]... logic handles the fact that odd and even rows have different indexing patterns due to the checkerboard arrangement. For each position that should contain an octahedron, it calls makeOcta with the displaced center coordinates instead of the original ones:
The final visualization renders the complete deformed chainmail where each octahedron maintains its individual shape and rotation characteristics but sits at a displaced position:
​
The simulation above displays flexible deformation of chainmail, with the structure bending and responding to applied forces. Some octahedra begin to visually separate in high-stress regions. This separation is not a sign of physical breakage but a result of how the model is constructed as the octahedral units are not actually connected in a mechanical sense. In real chainmail, links are physically interlocked and do not separate under this kind of displacement. They distribute stress across the mesh, allowing the structure to remain intact even under high load. This highlights a key modeling limitation. While our setup can reproduce some aspects of chainmail behavior, capturing the true interlinking mechanics would require explicit constraints or joint-based connections. Nonetheless, the ability to control when and where separations occur still provides useful insight into how stress concentrates and propagates across a flexible mesh.
By slightly adjusting the Young’s modulus, changing the boundary conditions, and applying force at different locations, I was able to generate a wide variety of displacement patterns. A few examples are shown below:

Conclusion

This project showed how Wolfram Language can model complex chainmail geometries, simulate their displacement under force, and even classify their weave types using machine learning. I was able to recreate a flexible, fabric-like structure that responds to stress in ways visually similar to real chainmail, though not mechanically interlocked. The whole process reminded me that medieval armorers solved this same geometric puzzle without computers. They had to figure out the spacing relationships and interlocking patterns through trial and error, then reproduce them consistently by hand. The math I worked out (those offset calculations and axis-transformations) represents relationships they understood intuitively through years of metalworking experience. Wolfram Language made it possible to explore not only how these materials are built, but also how they behave when displaced. I was also able to quickly visualize, carry out machine learning, and easily tweak parameters of my constructor functions. This reinforced the idea that computational tools can help us better understand both materials science and historical engineering.

Future Directions

The next step is to add real connectivity between the octahedral units. By encoding constraints or joint-like behavior, the simulation could capture more realistic deformations showing how forces travel across the fabric and how failure spreads when connections break. Making some links stronger than others based on orientation would also reflect how real chainmail distributes stress unevenly. We can also explore more advanced behaviors, such as using sliders to vary ring thickness, spacing, or stiffness could help visualize how each factor affects strength and flexibility. Adding small random imperfections would show how well the structure handles real-world variation. Together, these improvements would move the model closer to simulating not just how chainmail looks, but also how it truly behaves.

References

◼(2021, August 11). Mechanical metamaterials with programmable compression-twist coupling. Nature. Retrieved July 1, 2025, from https://www.nature.com/articles/s41586-021-03698-7​
​
◼(2022, October 21). Chainmail Simulation. Wolfram Community. Retrieved July 1, 2025, from https://community.wolfram.com/groups/-/m/t/2664865​
​
◼(n.d.). Young’s modulus. Wikipedia. Retrieved July 1, 2025, from https://en.wikipedia.org/wiki/Young%27s_modulus​
​
◼(2012). ChainMail. Wolfram Demonstrations Project. Retrieved July 1, 2025, from https://demonstrations.wolfram.com/ChainMail/​
​
◼(2013, January 13). Japanese 6-in-1. The Mail Research and Appreciation Society. Retrieved July 1, 2025, from https://www.mailleartisans.org/articles/articledisplay.php?key=190

Acknowledgements

I want to thank my mentor Joseph for helping me turn what started as some scattered ideas about chainmail into an actual working project. His patience and guidance kept me on track when the geometry got confusing and the code seemed determined to break in new and creative ways. Thanks to the program directors for being incredibly supportive and welcoming throughout this whole process. Huge thanks to all the TAs who helped me debug my way through many Wolfram crashes and syntax errors. Special recognition goes to William and Anoushka, who always took the time to carefully explain the Wolfram documentation and patiently walked me through exactly where I went wrong. Thank you to the Lead TAs, Bertie and Anne, for being amazing people who are really fun to talk to and for helping throughout the project. Their enthusiasm and good humor made even the most frustrating days enjoyable. And finally, thank you to Stephen Wolfram for giving me this intriguing project idea.

CITE THIS NOTEBOOK

Interlocked: computational chainmail engineering​
by Rakhi Jain​
Wolfram Community, STAFF PICKS, July 10, 2025
​https://community.wolfram.com/groups/-/m/t/3501343