From Singularities to Dynkin Diagrams ====================================== Arnold's ADE Classification 1. The Setup: Critical Points of Smooth Functions --------------------------------------------------- Consider a smooth function :math:`f: \mathbb{R}^n \to \mathbb{R}`. A point :math:`x_0` is a **critical point** if all partial derivatives vanish: .. math:: \nabla f(x_0) = 0 The critical point is **non-degenerate** if the Hessian matrix .. math:: H_{ij} = \frac{\partial^2 f}{\partial x_i \partial x_j}(x_0) has full rank (:math:`\det H \neq 0`). By the **Morse Lemma**, every non-degenerate critical point can be brought to the normal form .. math:: f(x) = \pm x_1^2 \pm x_2^2 \pm \cdots \pm x_n^2 by a smooth change of coordinates. Non-degenerate critical points are completely classified by a single integer (the index = number of minus signs), and they are **stable**: small perturbations of :math:`f` don't change the local picture. The interesting story begins with **degenerate** critical points, where :math:`\det H = 0`. 2. Equivalence of Singularities --------------------------------- Two function germs :math:`f` and :math:`g` (functions defined near the origin with :math:`f(0) = g(0) = 0`, :math:`\nabla f(0) = \nabla g(0) = 0`) are **right-equivalent** if there exists a smooth change of coordinates :math:`\phi` near 0 such that: .. math:: g(x) = f(\phi(x)) This is the natural notion of "same singularity" -- if you can deform the domain to turn one function into the other, they have the same type. **Example.** :math:`f(x,y) = x^3 + y^2` and :math:`g(x,y) = x^3 + 2y^2` are right-equivalent (via :math:`\phi(x,y) = (x, y/\sqrt{2})`), but :math:`f(x,y) = x^3 + y^2` and :math:`h(x,y) = x^4 + y^2` are not. How do we prove inequivalence? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Showing that two singularities *are* equivalent is straightforward: exhibit the coordinate change :math:`\phi`. But how can we be certain that *no* smooth change of coordinates exists? The answer is **invariants** -- quantities that are computable from :math:`f` and that remain unchanged under *any* smooth coordinate substitution. If an invariant differs between :math:`f` and :math:`g`, no coordinate change can relate them. **Invariant 1: The Milnor number.** The most basic invariant is the **Milnor number** :math:`\mu`, defined as the dimension of the **local algebra** (also called the Jacobian algebra): .. math:: \mu(f) = \dim_\mathbb{R} \frac{\mathcal{O}_n}{J(f)}, \qquad J(f) = \left\langle \frac{\partial f}{\partial x_1}, \ldots, \frac{\partial f}{\partial x_n} \right\rangle Here :math:`\mathcal{O}_n` is the ring of smooth function germs at the origin, and :math:`J(f)` is the ideal generated by the partial derivatives. The quotient has finite dimension precisely when the singularity is *isolated*. The Milnor number is invariant under coordinate changes because if :math:`g = f \circ \phi`, the chain rule gives :math:`J(g) = J(f) \circ \phi` (up to an invertible Jacobian factor), so the quotient algebras are isomorphic. The ``mutation_game`` library can compute this: .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import milnor_number >>> x, y = symbols('x y') # define the symbolic variables >>> milnor_number(x**3 + y**2, (x, y)) # A2 singularity: mu = 2 2 >>> milnor_number(x**4 + y**2, (x, y)) # A3 singularity: mu = 3 3 **Example.** For :math:`f = x^3 + y^2` (type :math:`A_2`): .. math:: J(f) = \langle 3x^2, 2y \rangle The quotient :math:`\mathcal{O}_2 / \langle x^2, y \rangle` has basis :math:`\{1, x\}`, so :math:`\mu = 2`. For :math:`h = x^4 + y^2` (type :math:`A_3`): .. math:: J(h) = \langle 4x^3, 2y \rangle The quotient :math:`\mathcal{O}_2 / \langle x^3, y \rangle` has basis :math:`\{1, x, x^2\}`, so :math:`\mu = 3`. Since :math:`\mu(f) = 2 \neq 3 = \mu(h)`, no smooth coordinate change can transform :math:`f` into :math:`h`. **Invariant 2: The corank.** The **corank** of a singularity is the number of zero eigenvalues of the Hessian matrix at the critical point (equivalently, :math:`n` minus the rank of :math:`H`). This is invariant because the rank of the Hessian is preserved under smooth coordinate changes (which act on :math:`H` by congruence: :math:`H \mapsto J^\top H J` where :math:`J` is the Jacobian of :math:`\phi`, which is invertible). The corank separates the families immediately: - **Corank 1**: :math:`A_n` singularities (one degenerate direction) - **Corank 2**: :math:`D_n` and :math:`E_n` singularities (two degenerate directions) .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import corank >>> x, y = symbols('x y') >>> corank(x**3 + y**2, (x, y)) # A2: one degenerate direction 1 >>> corank(x**2*y + y**3, (x, y)) # D4: two degenerate directions 2 **Invariant 3: The local algebra itself.** The most powerful invariant is the full isomorphism class of the local algebra :math:`\mathcal{O}_n / J(f)`. The **Mather--Yau theorem** (1982) states that for isolated singularities, this is a *complete* invariant: *Two function germs* :math:`f` *and* :math:`g` *with isolated singularities are right-equivalent if and only if their local algebras are isomorphic as* :math:`\mathbb{R}`-*algebras.* This is a deep result: it says the algebraic structure of the quotient ring captures everything about the geometry of the singularity. The ADE normal forms are mutually inequivalent because their local algebras are pairwise non-isomorphic (distinct :math:`\mu` values, except :math:`D_n` and :math:`A_n` at the same :math:`n`, which are separated by the corank). The ``classify`` function automates the full classification: .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import classify >>> x, y = symbols('x y') >>> classify(x**3 + y**2, (x, y)) # uses mu and corank to determine type 'A2' >>> classify(x**2*y + y**3, (x, y)) # corank 2, mu=4 -> D4 'D4' >>> classify(x**3 + y**4, (x, y)) # corank 2, mu=6, pure cube 3-jet -> E6 'E6' How do we construct the coordinate change explicitly? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Knowing two singularities are equivalent (same invariants) doesn't hand us the map :math:`\phi`. There are three main techniques for constructing it. **Method 1: The homotopy method (Moser's path method).** Given :math:`f` and :math:`g` with the same type, define a one-parameter family: .. math:: F_t = (1-t) f + t g, \qquad t \in [0, 1] We seek a family of diffeomorphisms :math:`\phi_t` satisfying :math:`F_t \circ \phi_t = f` for all :math:`t`, with :math:`\phi_0 = \text{id}`. If we can write: .. math:: g(x) - f(x) = \sum_{i=1}^n a_i(x) \frac{\partial F_t}{\partial x_i}(x) then :math:`\dot{\phi}_t = -(a_1, \ldots, a_n)` defines a flow, and integrating from :math:`t = 0` to :math:`t = 1` gives :math:`\phi = \phi_1`. .. code-block:: pycon >>> from sympy import symbols, expand >>> from mutation_game import homotopy_equivalence >>> x, y = symbols('x y') >>> f = x**3 + y**2 # source singularity >>> g = x**3 + 5*y**2 # target (same type A2) >>> result = homotopy_equivalence(f, g, (x, y)) # find coord change >>> result['coordinate_change'] # the map phi such that g(phi(x,y)) = f(x,y) {x: x, y: sqrt(5)*y/5} >>> # verify: substituting phi into g recovers f >>> expand(g.subs(y, result['coordinate_change'][y])) x**3 + y**2 The coordinate change :math:`\phi(x,y) = (x, y/\sqrt{5})` transforms :math:`g` back into :math:`f`. **Method 2: Jet determination (finite order Taylor matching).** For finitely determined singularities, one eliminates higher-order terms order by order via polynomial coordinate substitutions: .. list-table:: :header-rows: 1 * - Type - Normal form - Determinacy * - :math:`A_n` - :math:`x^{n+1}` - :math:`(n+1)`-determined * - :math:`D_n` - :math:`x^2 y + y^{n-1}` - :math:`(n-1)`-determined * - :math:`E_6` - :math:`x^3 + y^4` - 4-determined * - :math:`E_7` - :math:`x^3 + xy^3` - 4-determined * - :math:`E_8` - :math:`x^3 + y^5` - 5-determined .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import jet_reduce >>> x = symbols('x') >>> # reduce x^3 + x^4 to A2 normal form u^3 >>> # by finding a coordinate change x = phi(u) that kills higher terms >>> result = jet_reduce(x**3 + x**4, x, 3) >>> result['normal_form'] # the target normal form u**3 >>> result['coordinate_change'] # x = u - u^2/3 + u^3/3 - ... -35*u**4/81 + u**3/3 - u**2/3 + u **Method 3: The Splitting Lemma.** Separates non-degenerate directions by completing the square: .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import splitting_lemma >>> x, y = symbols('x y') >>> # split f = x^2 + x*y^2 + y^4 into non-degenerate + residual parts >>> result = splitting_lemma(x**2 + x*y**2 + y**4, (x, y)) >>> result['quadratic_part'] # non-degenerate direction (Morse part) u0**2 >>> result['residual'] # remaining singularity in fewer variables 3*y**4/4 >>> result['corank'] # number of degenerate directions 1 The function :math:`x^2 + xy^2 + y^4` splits into :math:`u_0^2 + \frac{3}{4}y^4`, separating the non-degenerate :math:`x`-direction from the :math:`A_3` singularity in :math:`y`. 3. Simple Singularities ------------------------ A singularity is **simple** if a sufficiently small neighborhood of :math:`f` in function space contains only finitely many equivalence classes of singularities. **Arnold's Theorem (1972).** *The simple singularities are exactly:* .. list-table:: :header-rows: 1 * - Type - Normal form - Milnor number :math:`\mu` * - :math:`A_n` (:math:`n \geq 1`) - :math:`x^{n+1}` - :math:`n` * - :math:`D_n` (:math:`n \geq 4`) - :math:`x^2 y + y^{n-1}` - :math:`n` * - :math:`E_6` - :math:`x^3 + y^4` - 6 * - :math:`E_7` - :math:`x^3 + xy^3` - 7 * - :math:`E_8` - :math:`x^3 + y^5` - 8 The Milnor number counts the number of non-degenerate critical points the singularity splits into under a generic perturbation. .. note:: The normal forms are written in the minimal number of variables. In higher dimensions, add a non-degenerate quadratic: :math:`x_1^{n+1} \pm x_2^2 \pm \cdots \pm x_m^2`. This doesn't affect the classification (by the Splitting Lemma). 4. Why ADE? The Milnor Fiber and the Intersection Form ------------------------------------------------------- The connection to Dynkin diagrams is through topology. Here we work in the complex setting, considering :math:`f: \mathbb{C}^2 \to \mathbb{C}`. The Milnor Fiber ^^^^^^^^^^^^^^^^^ Given a singularity :math:`f` with :math:`f(0) = 0`, perturb it slightly to get :math:`f_t` (a Morsification). The fiber .. math:: F_t = \{x \in B_\varepsilon : f_t(x) = \delta\} is a smooth manifold called the **Milnor fiber**. For surface singularities in :math:`\mathbb{C}^2`, it is a surface of genus :math:`g` with boundary, where :math:`\mu` is the Milnor number. Vanishing Cycles ^^^^^^^^^^^^^^^^^ Each of the :math:`\mu` non-degenerate critical points of :math:`f_t` contributes a **vanishing cycle** :math:`\delta_i \in H_1(F_t, \mathbb{Z})` -- a loop that shrinks to a point as :math:`t \to 0`. The :math:`\mu` vanishing cycles form a basis of :math:`H_1(F_t, \mathbb{Z}) \cong \mathbb{Z}^\mu`. The Intersection Form ^^^^^^^^^^^^^^^^^^^^^^ The first homology carries a natural **intersection form**: .. math:: \langle \delta_i, \delta_j \rangle = \begin{cases} -2 & \text{if } i = j \\ 0 \text{ or } 1 & \text{if } i \neq j \end{cases} Defining :math:`C_{ij} = -\langle \delta_i, \delta_j \rangle` gives: - :math:`C_{ii} = 2` for all :math:`i` - :math:`C_{ij} = 0` or :math:`-1` for :math:`i \neq j` **This is exactly a Cartan matrix of ADE type.** The vanishing cycles that intersect are connected by an edge in the Dynkin diagram. The Result ^^^^^^^^^^^ .. list-table:: :header-rows: 1 * - Singularity - Normal form - Vanishing cycles - Intersection form * - :math:`A_n` - :math:`x^{n+1} + y^2` - :math:`n` cycles in a chain - :math:`A_n` Dynkin diagram * - :math:`D_n` - :math:`x^2 y + y^{n-1}` - :math:`n` cycles, chain + fork - :math:`D_n` Dynkin diagram * - :math:`E_6` - :math:`x^3 + y^4` - 6 cycles - :math:`E_6` Dynkin diagram * - :math:`E_7` - :math:`x^3 + xy^3` - 7 cycles - :math:`E_7` Dynkin diagram * - :math:`E_8` - :math:`x^3 + y^5` - 8 cycles - :math:`E_8` Dynkin diagram The **monodromy** acts as a **Coxeter element** of the Weyl group -- a product of all simple reflections :math:`s_1 s_2 \cdots s_n`. These are exactly the mutation matrices from the mutation game. 5. Worked Example: A\ :sub:`3` in Detail ------------------------------------------ We walk through the full analysis of :math:`f(x, y) = x^4 + y^2` step by step. **Step 1: Verify isolated singularity.** .. code-block:: pycon >>> from sympy import symbols, diff, solve >>> x, y = symbols('x y') # define symbolic variables >>> f = x**4 + y**2 # the A3 singularity (in two variables) >>> # compute partial derivatives >>> diff(f, x), diff(f, y) (4*x**3, 2*y) >>> # find critical points: where both partials vanish >>> solve([diff(f, x), diff(f, y)], [x, y]) [(0, 0)] The only critical point is the origin. **Step 2: Compute invariants.** .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import milnor_number, corank, classify >>> x, y = symbols('x y') >>> f = x**4 + y**2 >>> milnor_number(f, (x, y)) # dimension of the local algebra O/J(f) 3 >>> corank(f, (x, y)) # number of zero eigenvalues of the Hessian 1 >>> classify(f, (x, y)) # determine ADE type from mu and corank 'A3' The Milnor number is 3 (the singularity splits into 3 Morse points), the corank is 1 (one degenerate direction), and the type is :math:`A_3`. **Step 3: Inspect the local algebra.** .. code-block:: pycon >>> # The Jacobian ideal J(f) = <4x^3, 2y> >>> # Monomials not in the leading term ideal: {1, x, x^2} >>> # Therefore dim O/(J(f)) = 3 = mu The local algebra :math:`\mathcal{O}_2 / \langle x^3, y \rangle` has basis :math:`\{1, x, x^2\}`, confirming :math:`\mu = 3`. **Step 4: Morsification -- perturb to split critical points.** .. code-block:: pycon >>> from sympy import symbols, diff, Rational, nsolve >>> x, y = symbols('x y') >>> # perturb f = x^4 + y^2 by adding lower-order terms >>> ft = x**4 - Rational(3, 4)*x**2 - Rational(1, 10)*x + y**2 >>> dft_dx = diff(ft, x) # partial derivative of the perturbed function >>> dft_dx 4*x**3 - 3*x/2 - 1/10 >>> # find the 3 critical points numerically (setting y = 0) >>> for guess in [-1.0, 0.1, 0.8]: ... xc = nsolve(dft_dx, x, guess) # numerical root near guess ... vc = ft.subs([(x, xc), (y, 0)]) # critical value f(xc, 0) ... print(f" x = {float(xc):.4f}, f = {float(vc):.4f}") x = -0.5758, f = -0.0812 x = -0.0675, f = 0.0034 x = 0.6433, f = -0.2034 The singularity has split into 3 non-degenerate critical points, arranged along the :math:`x`-axis. Each contributes a vanishing cycle. **Step 5: The intersection pattern.** The 3 critical points are ordered on the real line: :math:`x_1 < x_2 < x_3`. Adjacent vanishing cycles intersect once, non-adjacent ones are disjoint: - :math:`\langle \delta_1, \delta_2 \rangle = 1` - :math:`\langle \delta_2, \delta_3 \rangle = 1` - :math:`\langle \delta_1, \delta_3 \rangle = 0` The intersection graph is a **path** :math:`\delta_1 - \delta_2 - \delta_3`, which is the :math:`A_3` Dynkin diagram. **Step 6: Connect to the mutation game.** .. code-block:: pycon >>> from mutation_game import MutationGame >>> # create the A3 mutation game from the Dynkin diagram >>> game = MutationGame.from_dynkin("A3") >>> # the Cartan matrix = negative of the intersection form >>> print(game.cartan_matrix()) [[ 2 -1 0] [-1 2 -1] [ 0 -1 2]] This is exactly the negative of the intersection matrix: :math:`C_{ij} = -\langle \delta_i, \delta_j \rangle`. .. code-block:: pycon >>> # enumerate all roots by BFS over mutation sequences >>> roots = game.calculate_roots() >>> pos = [r for r in roots if all(v >= 0 for v in r)] # positive roots only >>> print(f"{len(pos)} positive roots, {len(roots)} total") 6 positive roots, 12 total The monodromy of the singularity is the Coxeter element :math:`M_0 \cdot M_1 \cdot M_2`: .. code-block:: pycon >>> import numpy as np >>> # the Coxeter element = product of all mutation matrices >>> M = game.mutation_matrix(0) @ game.mutation_matrix(1) @ game.mutation_matrix(2) >>> print(M) [[ 0 0 -1] [ 1 0 -1] [ 0 1 -1]] The general case ^^^^^^^^^^^^^^^^^ For :math:`A_n`, take :math:`f(x, y) = x^{n+1} + y^2`. The Morsification .. math:: f_t(x, y) = x^{n+1} - t_1 x^{n-1} - t_2 x^{n-2} - \cdots - t_n x + y^2 splits the singularity into :math:`n` Morse points on the :math:`x`-axis. The vanishing cycles form a chain, giving the :math:`A_n` path graph. 6. Worked Example: D\ :sub:`4` in Detail ------------------------------------------ **Step 1: Verify singularity and compute invariants.** .. code-block:: pycon >>> from sympy import symbols, solve, diff, hessian >>> from mutation_game import milnor_number, corank, classify >>> x, y = symbols('x y') # define symbolic variables >>> f = x**2 * y + y**3 # the D4 singularity >>> # find critical points >>> solve([diff(f, x), diff(f, y)], [x, y]) [(0, 0)] >>> milnor_number(f, (x, y)) # dimension of local algebra 4 >>> corank(f, (x, y)) # both Hessian eigenvalues are zero 2 >>> classify(f, (x, y)) # mu=4, corank=2 -> D4 'D4' **Step 2: Inspect the Hessian.** .. code-block:: pycon >>> # compute the Hessian matrix of second derivatives >>> H = hessian(f, [x, y]) >>> # evaluate at the origin: all entries are zero (corank = 2) >>> H.subs([(x, 0), (y, 0)]) Matrix([[0, 0], [0, 0]]) The :math:`D_4` singularity is distinguished from :math:`A_3` by its corank. Its 3-jet :math:`x^2 y + y^3 = y(x^2 + y^2)` has a **repeated factor** in :math:`y`, unlike the :math:`E`-types whose 3-jet is a perfect cube. **Step 3: Morsification.** .. code-block:: pycon >>> from sympy import symbols, diff, solve, Rational, im >>> x, y = symbols('x y') >>> # perturb to split the singularity into 4 Morse points >>> ft = x**2*y + y**3 - Rational(1, 5)*y >>> # solve for critical points: set both partials to zero >>> sys = [diff(ft, x), diff(ft, y)] >>> crits = solve(sys, [x, y]) >>> # filter real solutions and print their positions and critical values >>> for c in crits: ... if im(c[0]) == 0 and im(c[1]) == 0: ... v = ft.subs([(x, c[0]), (y, c[1])]) # critical value ... print(f" ({float(c[0]):.4f}, {float(c[1]):.4f}), f = {float(v):.4f}") (0.0000, -0.2582), f = 0.0344 (0.0000, 0.2582), f = -0.0344 (-0.3651, -0.1291), f = 0.0172 (0.3651, -0.1291), f = 0.0172 Four critical points (matching :math:`\mu = 4`). Note the **fork structure**: the critical points are no longer collinear. Two of them share the same critical value, reflecting the fork in the :math:`D_4` diagram. **Step 4: Connect to the mutation game.** .. code-block:: pycon >>> from mutation_game import MutationGame >>> # create D4 from its Dynkin diagram name >>> game = MutationGame.from_dynkin("D4") >>> # adjacency matrix: node 1 is the hub connecting to 0, 2, and 3 >>> print(game.adj) [[0 1 0 0] [1 0 1 1] [0 1 0 0] [0 1 0 0]] >>> # compute the full root system >>> roots = game.calculate_roots() >>> pos = [r for r in roots if all(v >= 0 for v in r)] # positive roots >>> print(f"{len(pos)} positive roots, {len(roots)} total") 12 positive roots, 24 total The general case ^^^^^^^^^^^^^^^^^ For :math:`D_n` (:math:`n \geq 4`), :math:`f = x^2 y + y^{n-1}` has :math:`\mu = n`. After Morsification, the :math:`n` vanishing cycles arrange as a chain of :math:`n-2` with two cycles forking off the end -- the :math:`D_n` Dynkin diagram. 7. The E-type Singularities ----------------------------- The exceptional cases: .. code-block:: pycon >>> from sympy import symbols >>> from mutation_game import milnor_number, corank, classify >>> x, y = symbols('x y') >>> # classify all three exceptional singularities >>> for name, f_expr in [('E6', x**3 + y**4), ... ('E7', x**3 + x*y**3), ... ('E8', x**3 + y**5)]: ... mu = milnor_number(f_expr, (x, y)) # local algebra dimension ... cr = corank(f_expr, (x, y)) # Hessian corank ... tp = classify(f_expr, (x, y)) # ADE type ... print(f" {name}: f = {f_expr}, mu = {mu}, corank = {cr}, type = {tp}") E6: f = x**3 + y**4, mu = 6, corank = 2, type = E6 E7: f = x**3 + x*y**3, mu = 7, corank = 2, type = E7 E8: f = x**3 + y**5, mu = 8, corank = 2, type = E8 All three have corank 2. They are distinguished from the :math:`D`-types by their 3-jet: the :math:`E`-types have a **pure cube** :math:`x^3` in their lowest-order terms, while :math:`D`-types have a reducible cubic :math:`x^2 y`. - **E6**: 6 vanishing cycles in the :math:`E_6` pattern (chain of 5 with one branch off the third node) - **E7**: 7 vanishing cycles in the :math:`E_7` pattern - **E8**: 8 vanishing cycles in the :math:`E_8` pattern -- the most complex simple singularity 8. Thom's Seven Catastrophes ------------------------------ Thom's catastrophe theory studies how families of functions depend on **control parameters**. The **codimension** is the number of parameters in the universal unfolding. .. list-table:: :header-rows: 1 * - Type - Normal form - Codimension - Universal unfolding * - :math:`A_2` - :math:`x^3` - 1 - :math:`x^3 + ax` * - :math:`A_3` - :math:`x^4` - 2 - :math:`x^4 + ax^2 + bx` * - :math:`A_4` - :math:`x^5` - 3 - :math:`x^5 + ax^3 + bx^2 + cx` * - :math:`A_5` - :math:`x^6` - 4 - :math:`x^6 + ax^4 + bx^3 + cx^2 + dx` * - :math:`D_4^-` - :math:`x^3 - xy^2` - 3 - :math:`x^3 - xy^2 + a(x^2+y^2) + bx + cy` * - :math:`D_4^+` - :math:`x^3 + xy^2` - 3 - :math:`x^3 + xy^2 + a(x^2+y^2) + bx + cy` * - :math:`D_5` - :math:`x^2y + y^4` - 4 - :math:`x^2y + y^4 + ay^2 + bx^2 + cy + dx` In any generic family with **at most 4 control parameters**, only these seven types appear. Their traditional names: .. list-table:: :header-rows: 1 * - ADE type - Catastrophe name - Codimension - Geometry * - :math:`A_2` - **Fold** - 1 - Two sheets merging * - :math:`A_3` - **Cusp** - 2 - Cusp of a caustic * - :math:`A_4` - **Swallowtail** - 3 - Self-intersecting surface * - :math:`A_5` - **Butterfly** - 4 - Butterfly-shaped bifurcation set * - :math:`D_4^-` - **Hyperbolic umbilic** - 3 - Wave crests on shallow water * - :math:`D_4^+` - **Elliptic umbilic** - 3 - Light focusing patterns * - :math:`D_5` - **Parabolic umbilic** - 4 - Transition between hyperbolic and elliptic The remaining ADE types have codimension :math:`\geq 5` and require special tuning to produce. This is why Thom stopped at seven. 9. Summary: The Chain of Connections -------------------------------------- .. math:: \boxed{\text{Simple singularity}} \xrightarrow{\text{Morsification}} \boxed{\text{Vanishing cycles}} \xrightarrow{\text{Intersection form}} \boxed{\text{Cartan matrix}} \xleftarrow{\text{Mutation game}} \boxed{\text{Dynkin diagram}} 1. Start with a degenerate critical point of a smooth function [AGV1985]_ 2. Perturb it to split into :math:`\mu` non-degenerate critical points [Milnor1968]_ 3. Each critical point contributes a vanishing cycle in the Milnor fiber 4. The intersection numbers of vanishing cycles give the Cartan matrix [Brieskorn1968]_ 5. The Cartan matrix is the same one from the mutation game on the Dynkin diagram [Slodowy1980]_ 6. The monodromy = product of Picard--Lefschetz reflections = Coxeter element For the role of catastrophe theory in this picture, see [Thom1975]_. References ----------- .. [AGV1985] V. I. Arnold, S. M. Gusein-Zade, A. N. Varchenko, *Singularities of Differentiable Maps*, Vol. I, Birkhauser, 1985. .. [Thom1975] R. Thom, *Structural Stability and Morphogenesis*, Benjamin, 1975. .. [Milnor1968] J. W. Milnor, *Singular Points of Complex Hypersurfaces*, Annals of Mathematics Studies 61, Princeton, 1968. .. [Brieskorn1968] E. Brieskorn, "Die Auflosung der rationalen Singularitaten holomorpher Abbildungen," *Math. Annalen* 178 (1968), 255--270. .. [Slodowy1980] P. Slodowy, *Simple Singularities and Simple Algebraic Groups*, Lecture Notes in Mathematics 815, Springer, 1980.