Chapter 2
12 min read
Section 11 of 70

What Is a Group?

Mathematics of Symmetry — Group Theory Essentials

Learning Objectives

In Chapter 1 we learned to see the symmetries of a crystal — the rotations, reflections, inversions, and improper rotations that map a lattice onto itself. In this chapter we learn to compute with them. Symmetry stops being a picture and becomes algebra. The first stepping stone is the most important word in the chapter: group.

By the end of this section you will be able to:

  1. State the four group axioms — closure, associativity, identity, and inverses — and decide, by inspection of a small set, whether they hold.
  2. Recognise two prototype groups that we will reuse for the rest of the chapter: the integers under addition (an infinite, abelian group) and D3D_3, the symmetries of an equilateral triangle (a finite, non-abelian group of order 6).
  3. Build and read a Cayley (multiplication) table, and use the Latin-square test to verify the group axioms at a glance.
  4. Compute the order of a group, decide whether it is abelian, and identify all of its subgroups.
  5. Connect the abstract definition to a real VASP / spglib output line: see exactly where the order G|G| appears, why improper operations are flagged with det=1\det = -1, and why this number sets a hard ceiling on the speed-up VASP can extract from your calculation.
The big idea: a crystal's symmetries are not just a list — they are a structured list. Composing two symmetries always gives a third symmetry of the same crystal. That “always” is the defining feature of a group, and it is the reason every theorem in this chapter has teeth.

From Symmetry to Algebra

Imagine you blink and someone rotates a crystal by 120120^\circ about a 3-fold axis. You open your eyes — and you cannot tell that anything has happened. The atoms are exactly where they were. Now the prankster does it again. Still indistinguishable. A third rotation brings the crystal back to its starting orientation. We have just observed three different operations on the crystal — a rotation by 120°, by 240°, and by 360° — and every one of them produced the same physical configuration.

Two questions arise immediately, and they are the questions that gave birth to group theory:

  1. Composition. If I do RR first and then SS, I have done some new operation SRSR. Is this new thing also a symmetry of the crystal? (Spoiler: yes, always.)
  2. Reversal. Every symmetry should be undoable — there should be another symmetry that puts everything back. Is that true? (Spoiler: yes, always.)

The minute you write down those two demands carefully, you are no longer doing geometry. You are doing algebra. The set of symmetries of an object — together with the rule for composing two of them — has exactly the structure that nineteenth-century mathematicians (Galois, Cauchy, Cayley) had isolated and called a group. The pay-off is enormous: every theorem about abstract groups is automatically a theorem about symmetries of crystals. The selection rules in spectroscopy, the systematic absences in diffraction, the irreducible representations that label your DFT band states — all of it falls out of one tiny set of axioms.

A historical aside

Galois introduced groups in 1832 to study the roots of polynomial equations, not crystals. The fact that the same axioms describe both is one of mathematics' most extraordinary unifications. When you fire up VASP and read G=48|G| = 48 in the OUTCAR, you are reaping a harvest planted by a 20-year-old duellist.

The Four Axioms — Definition of a Group

A group is a pair (G,)(G, \,\cdot\,) consisting of a set GG and a binary operation :G×GG\cdot \, : G \times G \rightarrow G (read: “the product of any two elements of GG is again an element of GG”) satisfying four axioms. The operation \cdot is usually written as juxtaposition, so we write ghgh instead of ghg \cdot h.

(G1) Closure:g,hG,  ghG\textbf{(G1) Closure:} \quad \forall \, g, h \in G, \; gh \in G
(G2) Associativity:g,h,kG,  (gh)k=g(hk)\textbf{(G2) Associativity:} \quad \forall \, g, h, k \in G, \; (gh)k = g(hk)
(G3) Identity:eG   s.t.   eg=ge=g    gG\textbf{(G3) Identity:} \quad \exists \, e \in G \; \text{ s.t. } \; eg = ge = g \;\; \forall \, g \in G
(G4) Inverses:gG,  g1G   s.t.   gg1=g1g=e\textbf{(G4) Inverses:} \quad \forall \, g \in G, \; \exists \, g^{-1} \in G \; \text{ s.t. } \; g g^{-1} = g^{-1} g = e

That is the entire definition. Four lines. Memorising the lines is easy; understanding why each one is non-negotiable takes a moment of staring at concrete examples — which is what we do next.

Axiom 1 — Closure

Closure says: the operation can't leak out of the set. If you take any two members of GG, multiply them, the result must still be inside GG. For symmetry operations this is almost a tautology: if rotating a crystal by 120120^\circ leaves it invariant, and reflecting it across a mirror plane also leaves it invariant, then doing the rotation and then the reflection still leaves it invariant. Therefore the composition is again a symmetry. The set is closed.

Counter-example sharpens the idea

The set of 9090^\circ rotations of a square is not closed under composition unless we include also the 180180^\circ and 270270^\circ rotations and the identity. Closure forces the set to grow until every product lives inside it. This is how groups generate themselves from a few seed operations.

Axiom 2 — Associativity

Associativity says: parentheses don't matter. When you compose AA, BB, and CC in that order, you get the same result whether you first do ABAB and then apply CC, or first do BCBC and then apply that to whatever AA is acting on. Geometrically: doing three transformations in a fixed order is one well-defined motion of the universe — re-grouping which two you mentally bundle together can't change the final position of an atom.

For matrices this is automatic: matrix multiplication is associative because ((AB)C)ik=j(AB)ijCjk=j,AiBjCjk=(A(BC))ik((AB)C)_{ik} = \sum_j (AB)_{ij} C_{jk} = \sum_{j,\ell} A_{i\ell} B_{\ell j} C_{jk} = (A(BC))_{ik}. Since every crystallographic symmetry is a matrix, associativity is free.

Associativity is not the same as commutativity. We will see in a moment that rs1s1rr \cdot s_1 \neq s_1 \cdot r in the triangle group D3D_3. Order matters; bundling does not.

Axiom 3 — Identity

The identity says: doing nothing is a thing. There must be a special element eGe \in G that, when composed with any gg, returns gg. For symmetries the identity is the “leave every atom where it is” operation — physically trivial, mathematically essential. Without it we could never write gg1=eg \cdot g^{-1} = e, so we could never express the idea of an inverse.

A nice consequence: the identity is unique. If ee and ee' were both identities, then e=ee=ee = e \cdot e' = e'. So we can speak of the identity, never an identity.

Axiom 4 — Inverses

Every symmetry is reversible. If you rotate a crystal by +120+120^\circ, the rotation by 120-120^\circ (equivalently +240+240^\circ) is also a symmetry, and the two compose to the identity. If you reflect across a mirror plane, doing it again undoes it. In matrix language this is the statement that every symmetry matrix is invertible — and indeed every orthogonal matrix is, with inverse equal to its transpose.

Inverses are unique

From gh1=eg h_1 = e and gh2=eg h_2 = e we get h1=eh1=(h2g)h1=h2(gh1)=h2e=h2h_1 = e h_1 = (h_2 g) h_1 = h_2 (g h_1) = h_2 e = h_2. So we may write g1g^{-1} without ambiguity — every element has exactly one inverse.

Example 1 — Integers Under Addition

Before we charge into crystal symmetries, let us verify the axioms in a setting every student already knows. Take G=ZG = \mathbb{Z} (the integers ,2,1,0,1,2,\ldots, -2, -1, 0, 1, 2, \ldots) and let the operation be ordinary addition.

AxiomCheckVerdict
G1 ClosureSum of two integers is an integerYes
G2 Associativity(a+b)+c = a+(b+c) for all integersYes
G3 Identity0 + n = n + 0 = n for every nYes (e = 0)
G4 Inversesn + (-n) = 0 for every nYes (n^-1 = -n)

All four axioms hold, so (Z,+)(\mathbb{Z}, +) is a group. It also happens to satisfy a+b=b+aa + b = b + a, so it is abelian — but commutativity is not part of the definition. It is a bonus property that some groups have and others (like the triangle group below) emphatically do not. (Z,+)(\mathbb{Z}, +) is also infinite: you can keep adding 1 forever. A crystal's point group is by contrast always finite — but the lattice translation group is infinite, and (Z,+)(\mathbb{Z}, +) is its 1D model.

Why this example matters for crystals

Translations along a 1D crystal axis form exactly (Z,+)(\mathbb{Z}, +): shift by nn lattice vectors, then by mm more, and you have shifted by n+mn + m. The infinite translation group of a 3D crystal is just (Z,+)×(Z,+)×(Z,+)(\mathbb{Z}, +) \times (\mathbb{Z}, +) \times (\mathbb{Z}, +) — a direct product of three copies of this baby example.

Example 2 — Symmetries of an Equilateral Triangle

Now the example you came here for. Take an equilateral triangle in a plane, with vertices labelled 11, 22, 33. Which rigid motions map the triangle to itself, paying no attention to the labels? There are exactly six:

ElementGeometric meaningPermutation of (1, 2, 3)
eIdentity — leave every atom where it is(1, 2, 3) — fix all
rRotate by +120 deg about the centre(2, 3, 1)
r^2Rotate by +240 deg about the centre(3, 1, 2)
s_1Reflect across the axis through vertex 1(1, 3, 2)
s_2Reflect across the axis through vertex 2(3, 2, 1)
s_3Reflect across the axis through vertex 3(2, 1, 3)

This six-element set is the dihedral group D3D_3 (also written D3hD_{3h} when we sit it in 3D and add an horizontal mirror). It is the smallest non-abelian group: rs1s1rr \cdot s_1 \neq s_1 \cdot r, as you can verify in the lab below. And although it has only six elements, every feature you will meet later in the chapter — irreducible representations, character tables, selection rules — already shows up here in miniature.

Each element is a 2×22 \times 2 orthogonal matrix in the plane. With vertex 1 placed at the top of the triangle, the matrices are:

r=(12323212)r = \begin{pmatrix} -\tfrac{1}{2} & -\tfrac{\sqrt{3}}{2} \\[3pt] \tfrac{\sqrt{3}}{2} & -\tfrac{1}{2} \end{pmatrix}, r2=(12323212)r^2 = \begin{pmatrix} -\tfrac{1}{2} & \tfrac{\sqrt{3}}{2} \\[3pt] -\tfrac{\sqrt{3}}{2} & -\tfrac{1}{2} \end{pmatrix}, s1=(1001)s_1 = \begin{pmatrix} -1 & 0 \\ 0 & 1 \end{pmatrix}, s2=(12323212)s_2 = \begin{pmatrix} \tfrac{1}{2} & \tfrac{\sqrt{3}}{2} \\[3pt] \tfrac{\sqrt{3}}{2} & -\tfrac{1}{2} \end{pmatrix}, s3=(12323212)s_3 = \begin{pmatrix} \tfrac{1}{2} & -\tfrac{\sqrt{3}}{2} \\[3pt] -\tfrac{\sqrt{3}}{2} & -\tfrac{1}{2} \end{pmatrix}.

Notice the determinants: detr=detr2=+1\det r = \det r^2 = +1 (proper rotations) and dets1=dets2=dets3=1\det s_1 = \det s_2 = \det s_3 = -1 (improper). This proper/improper split is the same one we met in Chapter 1 — and it is exactly the det=±1\det = \pm 1 column you will see in the spglib output at the end of this section.


Interactive D₃ Lab

The fastest way to build genuine intuition for a group is to play with one. Click the buttons below to compose D₃ operations in any order. The triangle morphs from its starting position to the final state. Watch three things happen simultaneously:

  • The click sequence at the top right grows — every click adds one factor to the composition.
  • The whole sequence collapses, in real time, to a single element of D₃ (shown in green). This is closure: no matter how many you stack, you never escape the six-element set.
  • The Cayley table at the bottom highlights, in green, the cell that justifies the latest binary step. After many clicks you will have lit up enough cells to convince yourself the whole table is correct.

D3 Symmetry Lab — click operations to compose them

123

Cyan: rotations  ·  Amber: reflections

Click sequence (apply left-to-right)
— click any button to start —
Reduces to a single group element
=e= e
Matrix W
(1001)\begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}
detW=1\det W = 1  proper
Vertex permutation
(123123)\begin{pmatrix} 1 & 2 & 3 \\ 1 & 2 & 3 \end{pmatrix}
Top: original. Bottom: where it lands.
Cayley table (row · col = first col, then row)
·eerrr2r^2s1s_1s2s_2s3s_3
eeeerrr2r^2s1s_1s2s_2s3s_3
rrrrr2r^2ees3s_3s1s_1s2s_2
r2r^2r2r^2eerrs2s_2s3s_3s1s_1
s1s_1s1s_1s2s_2s3s_3eer2r^2rr
s2s_2s2s_2s3s_3s1s_1rreer2r^2
s3s_3s3s_3s1s_1s2s_2r2r^2rree

Notice: every row and every column contains each of the six elements exactly once. This is a Latin square — the unmistakable fingerprint of a group.

A few experiments worth running before you read on:

  1. Click rr three times. The sequence reduces to ee: a 360° rotation is the identity. Equivalently, r3=er^3 = e — the order of rr as an element is 3.
  2. Click any reflection twice. The triangle returns to its starting position. So sk2=es_k^2 = e for every kk: every reflection is its own inverse.
  3. Click rr then s1s_1. The result is s3s_3. Now reset and click s1s_1 then rr. The result is s2s_2. Different. This is the proof, in your hands, that D3D_3 is non-abelian.
  4. Click any operation followed by its inverse (for reflections, click it twice; for rr, click rr then r2r^2). You always land on ee. That is axiom G4 in motion.

Reading the Cayley Table

The 6×6 grid in the lab is the Cayley table (or multiplication table) of D3D_3. The convention is: the entry at row gg, column hh is the product ghg \cdot h, meaning “apply hh first, then gg.”

Two visual properties of the table tell you instantly that D3D_3 is a group:

  • The identity row and column repeat the headers. The ee row reads exactly e,r,r2,s1,s2,s3e, r, r^2, s_1, s_2, s_3. That is axiom G3.
  • Every element appears exactly once in every row, and exactly once in every column. That is the Latin-square property, and it is equivalent to the existence of inverses (G4) plus closure (G1). Whenever you build a multiplication table of a finite group, this pattern must emerge — if it doesn't, you have made an arithmetic error or your set is not a group.

The table also reveals non-commutativity at a glance: it is not symmetric across its main diagonal. The entry at (r,s1)(r, s_1) is s3s_3, but the entry at (s1,r)(s_1, r) is s2s_2. Reflect the table across its diagonal and it changes — which means the group operation is not commutative.


Order, Abelian, and Subgroups

Three pieces of basic vocabulary will recur in every chapter and every VASP run. Memorise them now.

Order of a group

The order of a finite group GG, written G|G|, is simply the number of elements. For D3D_3, D3=6|D_3| = 6. For the cubic point group OhO_h (which we will meet later) it is Oh=48|O_h| = 48. For the integers, Z=|\mathbb{Z}| = \infty. We also speak of the order of an element: the smallest positive integer nn such that gn=eg^n = e. In D3D_3, the order of rr is 3 and the order of every sks_k is 2.

Abelian groups

A group is abelian (after Niels Abel) if gh=hggh = hg for every pair g,hGg, h \in G. The integers under addition are abelian; D3D_3 is not. Every cyclic group — a group generated by a single element, like {e,r,r2}\{e, r, r^2\} inside D3D_3 — is abelian. Whether your crystal's point group is abelian decides things as practical as whether all of its irreducible representations are one-dimensional (abelian → yes; non-abelian → there will be 2D or 3D irreps).

Subgroups

A subgroup HGH \subseteq G is a subset that is itself a group under the same operation. D3D_3 has six subgroups:

SubgroupOrderDescription
{e}1Trivial subgroup — always present
{e, s_1}2Cyclic, generated by reflection s_1
{e, s_2}2Cyclic, generated by reflection s_2
{e, s_3}2Cyclic, generated by reflection s_3
{e, r, r^2}3Cyclic, generated by the rotation r — the rotation subgroup C_3
D_3 itself6Improper subgroup — the whole group

Notice every subgroup's order divides D3=6|D_3| = 6. That is no coincidence — it is Lagrange's theorem: the order of any subgroup divides the order of the group. Lagrange will reappear when we count how many irreducible representations a group has and when we figure out how many k-points are equivalent in the Brillouin zone.

The rotation subgroup {e,r,r2}=C3\{e, r, r^2\} = C_3 is the most important subgroup for crystallographers. When a crystal possesses only rotations and no reflections (rare but possible), its point group is purely cyclic and it is necessarily chiral.

Why This Matters for Crystals

Everything in the rest of the chapter is built from the four axioms. Three direct pay-offs are worth previewing now:

  1. Point groups (next sections). Every crystal's set of point symmetries is a group — one of the 32 crystallographic point groups. The four axioms guarantee that a crystal cannot have a “rogue” symmetry that fails to compose with the others; the symmetry list is structurally complete.
  2. Representations and character tables. Every group acts on a vector space; the way it acts is a representation. Decomposing those representations into irreducible pieces gives us the labels we use for orbitals, phonons, and band states. Without group axioms, decomposition makes no sense.
  3. Selection rules. A matrix element ψiO^ψj\langle \psi_i | \hat{O} | \psi_j \rangle is forced to zero whenever the product of the three irreducible labels does not contain the trivial representation. That single rule explains every “forbidden transition” in optical, IR, and Raman spectra. It is a one-page consequence of the group axioms plus orthogonality.
The most-used theorem in this book. If GG is the symmetry group of a crystal and G=N|G| = N, then in any Brillouin-zone integral the number of k-points VASP actually has to compute is at most Nfull/NN_\text{full} / N. The factor NN is the order of the group. Mastering this single section is what turns “120,000120{,}000 k-points” into “2,5002{,}500 k-points” on your screen.

VASP Connection — Group Order in spglib

Time to make the abstract definition concrete. VASP's symmetry analysis (and the OUTCAR line “Found N space group operations”) is powered under the hood by spglib. We will reproduce its analysis from Python on a tiny structure designed to have exactly D3D_3 symmetry — three identical atoms at the vertices of an equilateral triangle inside a hexagonal cell.

Click any line of the code below to see what each variable holds, exactly which arguments each library function consumes, and the output value at that line. Note especially the loop trace: every one of the six rotation matrices spglib returns is shown explicitly, and you can match each one to an element of D3D_3 from the lab above.

Computing |D₃| with spglib
🐍d3_with_spglib.py
1import numpy as np

NumPy gives us fast N-dimensional arrays plus the linear-algebra helpers (matrix multiply, determinant) we need to inspect the symmetry operations spglib returns.

EXECUTION STATE
numpy = Numerical-array library — used here for the lattice vectors, fractional positions, and np.linalg.det on each rotation matrix.
2import spglib

spglib is the de-facto symmetry-finder used by VASP, ASE, pymatgen, and many DFT toolchains. It analyses a (lattice, positions, species) tuple and returns the full set of crystallographic symmetry operations — the very group G this section is about.

EXECUTION STATE
spglib.get_symmetry = Returns a dict with 'rotations' (N × 3 × 3 integer matrices) and 'translations' (N × 3 fractional vectors). The number N is the *order* of the space group.
5Lattice constant a = 3.0 Å

Pick a hexagonal in-plane lattice with a = 3 Å. The exact value does not change the symmetry — only the geometry decides the group. We use 3 Å so the visualization is on a familiar scale (close to graphene's 2.46 Å, ZnO's 3.25 Å).

EXECUTION STATE
a = 3.0 — in-plane lattice parameter, in Å
6lattice = ... (3×3 matrix)

Stack the three lattice vectors as ROWS of a 3×3 matrix. We choose a hexagonal frame: a along x, b at 120° to a, c orthogonal and large. Hexagonal lattices admit 3-fold rotations, which is exactly the symmetry we want our triangular motif to enjoy.

EXECUTION STATE
row 0 (a vector) = [3.0, 0.0, 0.0] — points along +x
row 1 (b vector) = [-1.5, 2.598, 0.0] — 120° from a, same length
row 2 (c vector) = [0.0, 0.0, 10.0] — long c so layers don't interact
→ why 120°? = A hexagonal cell has a · b = -|a||b|/2. Two vectors at 120° preserve 3-fold and 6-fold rotational symmetry.
13positions — three identical atoms at triangle vertices

Three identical atoms placed at the vertices of an equilateral triangle inside the unit cell. Because every atom is the *same species* and arranged with full triangular symmetry, the resulting symmetry group will contain all six D₃ operations: e, r, r², s₁, s₂, s₃.

EXECUTION STATE
positions (3×3, fractional) =
      x      y     z
0   1/3   1/3   0.5
1   2/3   1/3   0.5
2   1/3   2/3   0.5
→ fractional? = Each row is a coefficient triple (u, v, w) such that the actual atom sits at u·a + v·b + w·c. Fractional coords decouple symmetry from the choice of a.
18numbers = [1, 1, 1] — all atoms identical

Atomic-number list (here all hydrogen, Z=1). Every atom must be the same species for the full triangular symmetry to survive. If we changed one to Z=8 (oxygen), we would break two of the three reflections and lose half the group.

EXECUTION STATE
numbers = [1, 1, 1] — three atoms, all element Z=1
→ try this = Change to [1, 8, 1]: spglib will return only |G| = 2 (identity + one reflection). The 3-fold rotation no longer maps atom→atom.
20cell = (lattice, positions, numbers)

spglib's universal input format: a 3-tuple of (3×3 lattice, N×3 positions, length-N atomic numbers). Every symmetry-finder in computational materials science consumes essentially this same triple.

EXECUTION STATE
cell = Tuple of (lattice, positions, numbers) — sufficient to define the structure and ask any symmetry question.
23sym = spglib.get_symmetry(cell, symprec=1e-5)

This single call computes the entire space group of our crystal. spglib first finds the point-group operations (rotations that fix the lattice), then the translation parts that complete each into a space-group operation, then returns them all. The dictionary has matching 'rotations' and 'translations' arrays.

EXECUTION STATE
📚 spglib.get_symmetry = Searches for every (R, t) pair such that R · positions + t reproduces the original positions modulo the lattice. Returns one (R, t) per symmetry operation.
⬇ arg 1: cell = Our (lattice, positions, numbers) tuple — describes WHAT to analyse.
⬇ arg 2: symprec=1e-5 = Tolerance in fractional coords for matching atoms. 1e-5 ≈ 30 µÅ on a 3 Å cell — strict enough to reject numerical noise, loose enough for converged DFT geometries. Larger values (1e-3) help relaxed structures, but can over-symmetrise.
⬆ result: sym = {'rotations': ndarray (N, 3, 3, int), 'translations': ndarray (N, 3, float), 'equivalent_atoms': ndarray (n_atoms,), ...} — a dict; we only need 'rotations' for this lesson.
24n_ops = len(sym["rotations"])

The length of the rotations array is exactly |G|, the *order* of the symmetry group. For our equilateral-triangle motif this prints 6 — one for each element of D₃ (e, r, r², s₁, s₂, s₃) — confirming the abstract analysis we did by hand.

EXECUTION STATE
len(sym['rotations']) = Counts how many 3×3 matrices spglib found. Equal to |G|.
⬆ n_ops = 6 — the order of the dihedral group D₃ for this motif.
25print(f"Order of the symmetry group: |G| = {n_ops}")

Display the group order. This is the single most important number to read off any spglib / VASP symmetry analysis: every k-point in the Brillouin zone can in principle be replaced by 1/|G| as many irreducible k-points, slashing computational cost by up to a factor of |G|.

EXECUTION STATE
f-string = Python f-string formatting — substitutes {n_ops} with its current value.
⬆ stdout = Order of the symmetry group: |G| = 6
28for k, R in enumerate(sym["rotations"]):

Walk through every group element. enumerate() pairs each 3×3 rotation matrix R with its index k in the list. We will compute the determinant of each and label it proper (+1, pure rotation) or improper (-1, contains a reflection).

EXECUTION STATE
📚 enumerate(iterable) = Built-in: yields (index, value) pairs. enumerate(['a','b','c']) → (0,'a'), (1,'b'), (2,'c'). Saves us from manually tracking k.
→ loop variable: k = 0, 1, 2, 3, 4, 5 — one per group element.
→ loop variable: R = A 3×3 integer matrix in the *fractional* basis. Examples: identity, the 120° rotation, the three mirror reflections.
LOOP TRACE · 6 iterations
k=0 (identity e)
R = [[ 1, 0, 0], [ 0, 1, 0], [ 0, 0, 1]]
det = +1 (proper)
k=1 (rotation r = +120°)
R = [[ 0, -1, 0], [ 1, -1, 0], [ 0, 0, 1]]
det = +1 (proper)
→ why integer entries? = In the fractional (lattice) basis a rotation maps lattice points to lattice points, so its matrix is an integer matrix.
k=2 (rotation r² = +240°)
R = [[-1, 1, 0], [-1, 0, 0], [ 0, 0, 1]]
det = +1 (proper)
k=3 (reflection s₁)
R = [[-1, 1, 0], [ 0, 1, 0], [ 0, 0, 1]]
det = -1 (improper)
k=4 (reflection s₂)
R = [[ 1, 0, 0], [ 1, -1, 0], [ 0, 0, 1]]
det = -1 (improper)
k=5 (reflection s₃)
R = [[ 0, -1, 0], [-1, 0, 0], [ 0, 0, 1]]
det = -1 (improper)
29det = int(round(np.linalg.det(R)))

Take the determinant of the 3×3 rotation matrix and round to the nearest integer. For any orthogonal symmetry operation the determinant is exactly +1 or −1; rounding cleans up the ~1e-16 floating-point noise.

EXECUTION STATE
📚 np.linalg.det(M) = Computes det(M) for any square matrix using LU decomposition. For 3×3 matrices it's effectively the textbook expansion.
round(x) = Built-in: rounds to the nearest integer. det = 0.999999... → 1.
int(...) = Cast to Python int so the print uses %+d formatting.
→ invariant = Every element of an orthogonal group has det = ±1. det classifies the operation: +1 proper, −1 improper.
30label = "proper" if det == +1 else "improper"

Conditional expression: labels the operation 'proper' (rotation, identity) when det = +1, 'improper' (reflection, inversion, improper rotation) when det = −1. This split is the most fundamental classification of crystallographic operations.

EXECUTION STATE
ternary expr = Python's `A if cond else B` — single-line conditional. Evaluates `cond`; returns A if true, otherwise B.
→ label values = 'proper' when det = +1 'improper' when det = −1
31print(f" op {k:2d}: det = {det:+d} ({label})")

Pretty-print one line per group element. The full output is a 1:1 readout of the abstract group D₃: 3 proper operations (the identity and two rotations) and 3 improper ones (the three reflections).

EXECUTION STATE
{k:2d} = Format index as a 2-wide decimal — keeps the printout aligned.
{det:+d} = Print the sign explicitly: +1 or -1.
⬆ full stdout =
Order of the symmetry group: |G| = 6
  op  0: det = +1  (proper)
  op  1: det = +1  (proper)
  op  2: det = +1  (proper)
  op  3: det = -1  (improper)
  op  4: det = -1  (improper)
  op  5: det = -1  (improper)
19 lines without explanation
1import numpy as np
2import spglib
3
4# Equilateral triangle of identical atoms in a hexagonal cell.
5# This 2D-like motif is the cleanest place to *see* a group of order 6.
6a = 3.0
7lattice = np.array([
8    [a, 0.0, 0.0],
9    [-a / 2, a * np.sqrt(3) / 2, 0.0],
10    [0.0, 0.0, 10.0],   # large c to decouple layers
11])
12
13# Three identical atoms placed at the vertices of an equilateral triangle
14# inside the unit cell, centred at the origin.
15positions = np.array([
16    [1 / 3, 1 / 3, 0.5],   # vertex 1
17    [2 / 3, 1 / 3, 0.5],   # vertex 2
18    [1 / 3, 2 / 3, 0.5],   # vertex 3
19])
20numbers = [1, 1, 1]   # all the same species
21
22cell = (lattice, positions, numbers)
23
24# Ask spglib for the symmetry group.
25sym = spglib.get_symmetry(cell, symprec=1e-5)
26n_ops = len(sym["rotations"])
27print(f"Order of the symmetry group: |G| = {n_ops}")
28
29# List every operation as a 3x3 rotation matrix in fractional coordinates.
30for k, R in enumerate(sym["rotations"]):
31    det = int(round(np.linalg.det(R)))
32    label = "proper" if det == +1 else "improper"
33    print(f"  op {k:2d}: det = {det:+d}  ({label})")

The expected output:

Order of the symmetry group: |G| = 6
  op  0: det = +1  (proper)
  op  1: det = +1  (proper)
  op  2: det = +1  (proper)
  op  3: det = -1  (improper)
  op  4: det = -1  (improper)
  op  5: det = -1  (improper)

Six operations. Three with det=+1\det = +1 (the rotations ee, rr, r2r^2) and three with det=1\det = -1 (the reflections s1s_1, s2s_2, s3s_3). This is exactly what the four axioms predict — and exactly what a VASP run on this structure would print near the top of its OUTCAR.

Try this

Edit the code above (in your own scratch file) and change numbers = [1, 1, 1] to numbers = [1, 8, 1]. spglib will now report G=2|G| = 2: only the identity and one mirror survive. Breaking equivalence between atoms breaks the group structure that depended on it. This is exactly how doping a crystal lowers its symmetry — and exactly the calculation you will run for Mn-doped CdSe in Chapter 7.

Summary

  1. A group is a set GG with a binary operation that satisfies four axioms: closure, associativity, identity, and inverses.
  2. The integers under addition (Z,+)(\mathbb{Z}, +) are an infinite abelian group, the model for crystal translations.
  3. The dihedral group D3D_3, with elements {e,r,r2,s1,s2,s3}\{e, r, r^2, s_1, s_2, s_3\}, is the smallest non-abelian group and the prototype for the rest of the chapter.
  4. The Cayley table of any group is a Latin square. Symmetry across its main diagonal characterises abelian groups.
  5. The order G|G| is the number of elements. Every subgroup's order divides G|G| (Lagrange).
  6. spglib (and through it, VASP) computes the symmetry group of a crystal automatically; reading its output is just reading the group's elements as 3×3 integer matrices in the fractional basis.
Looking ahead. In the next section we put groups to work on the 32 crystallographic point groups themselves — naming them, listing their elements, and building the multiplication table for each. The four axioms you just memorised will quietly do all the heavy lifting.
Loading comments...