Seminar 1: Ветвящиеся процессы Гальтона-Ватсона

Author

Carlos Buitrago

Пусть \(\xi\in\mathbb Z_+\) — случайная величина, описывающая число потомков одной частицы.

Пусть \(\left\{\xi_k^{(n)}:\ k,n\in\mathbb N\right\}\) — независимые случайные величины с тем же распределением, что и \(\xi\).

Определим \(X_0=1\), и для \(n\ge1\)

\[ X_n = \sum_{k=1}^{X_{n-1}} \xi_k^{(n)}. \]

NoteОпределение

Процесс \((X_n)_{n\ge0}\) называется ветвящимся процессом Гальтона–Ватсона с законом размножения \(\xi\).

Здесь

  • \(X_n\) — число частиц в \(n\)-м поколении;
  • \(\xi_k^{(n)}\) — число потомков \(k\)-й частицы поколения \(n-1\).

Главный вопрос этой главы:

\[ \boxed{ \text{Какова вероятность того, что процесс когда-нибудь выродится?} } \]

TipКак выглядит одна реализация процесса?

Для первого эксперимента возьмём \(\xi\sim\operatorname{Pois}(\lambda)\), поэтому \(\mu=\mathbb E\xi=\lambda\).

Сравним три режима:

\[ \lambda=0.8,\qquad \lambda=1.1,\qquad \lambda=2. \]

Show Python code
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from scipy import optimize

rng = np.random.default_rng(2026)

def simulate_gw_poisson(lam, generations=8, population_cap=5000, rng=None):
    # Simulate Galton-Watson generation sizes for Poisson offspring.
    if rng is None:
        rng = np.random.default_rng()
    x = [1]
    for _ in range(generations):
        if x[-1] == 0:
            x.append(0)
            continue
        nxt = rng.poisson(lam, size=x[-1]).sum()
        nxt = min(int(nxt), population_cap)
        x.append(nxt)
    return np.array(x, dtype=int)

def simulate_gw_tree_poisson(lam, generations=6, max_nodes=250, rng=None):
    # Simulate a finite genealogical tree.
    if rng is None:
        rng = np.random.default_rng()

    G = nx.DiGraph()
    levels = {0: [0]}
    G.add_node(0, generation=0)
    next_id = 1

    for gen in range(1, generations + 1):
        current = []
        for parent in levels.get(gen - 1, []):
            if len(G) >= max_nodes:
                break
            n_children = int(rng.poisson(lam))
            for _ in range(n_children):
                if len(G) >= max_nodes:
                    break
                child = next_id
                next_id += 1
                G.add_node(child, generation=gen)
                G.add_edge(parent, child)
                current.append(child)
        levels[gen] = current
        if not current:
            break
    return G, levels

def layered_positions(levels):
    # Position nodes by generation.
    pos = {}
    for gen, nodes in levels.items():
        m = len(nodes)
        if m == 0:
            continue
        xs = np.linspace(-1, 1, m) if m > 1 else np.array([0.0])
        for x, node in zip(xs, nodes):
            pos[node] = (x, -gen)
    return pos

fig, axes = plt.subplots(1, 3, figsize=(15, 4.8))

for ax, lam in zip(axes, [0.8, 1.1, 2]):
    local_rng = np.random.default_rng(int(1000 * lam) + 7)
    G, levels = simulate_gw_tree_poisson(
        lam, generations=6, max_nodes=180, rng=local_rng
    )
    pos = layered_positions(levels)

    nx.draw_networkx_edges(
        G, pos, ax=ax, arrows=False, width=0.8, alpha=0.6
    )
    nx.draw_networkx_nodes(
        G, pos, ax=ax, node_size=55
    )

    generation_sizes = [len(levels.get(g, [])) for g in range(7)]
    ax.set_title(
        rf"$\lambda={lam}$" + "\n" +
        rf"$X_n={generation_sizes}$"
    )
    ax.axis("off")

plt.suptitle("Три реализации процесса Гальтона–Ватсона", y=1.03, fontsize=15)
plt.tight_layout()
plt.show()

TipТри режима ветвящегося процесса

Главной характеристикой закона размножения является

\[ \mu=\mathbb E\xi. \]

Уже на уровне симуляций видно три качественно различных режима:

  • \(\mu<1\)докритический;
  • \(\mu=1\)критический;
  • \(\mu>1\)надкритический.

Особенно интересен критический случай: процесс может совершать большие случайные выбросы, хотя в дальнейшем всё равно вырождается с вероятностью \(1\).

Show Python code
def simulate_many_poisson(lam, n_paths=5, generations=30, seed=0):
    local_rng = np.random.default_rng(seed)
    paths = np.zeros((n_paths, generations + 1), dtype=float)
    paths[:, 0] = 1

    for i in range(n_paths):
        x = 1
        for n in range(1, generations + 1):
            if x == 0:
                paths[i, n:] = 0
                break
            x = int(local_rng.poisson(lam, size=x).sum())
            x = min(x, 200_000)
            paths[i, n] = x
    return paths

fig, axes = plt.subplots(1, 3, figsize=(15, 4.8), sharex=True)

for ax, lam, seed in zip(axes, [0.8, 1.0, 1.2], [10, 20, 30]):
    paths = simulate_many_poisson(lam, n_paths=30, generations=30, seed=seed)

    for path in paths:
        ax.plot(range(path.size), path, alpha=0.25, linewidth=1)

    ax.set_yscale("symlog", linthresh=1)
    ax.set_title(rf"$\mu=\lambda={lam}$")
    ax.set_xlabel("Поколение $n$")
    ax.grid(alpha=0.25)

axes[0].set_ylabel("$X_n$  (symlog)")
plt.suptitle("Много независимых траекторий $X_n$", y=1.02, fontsize=15)
plt.tight_layout()
plt.show()

1 Средний размер поколения

Из определения

\[ X_{n+1} = \sum_{k=1}^{X_n}\xi_k^{(n+1)} \]

получаем

\[ \mathbb E(X_{n+1}\mid X_n) = \mu X_n, \qquad \mu=\mathbb E\xi. \]

По формуле полного математического ожидания,

\[ \mathbb E X_{n+1} = \mu\,\mathbb E X_n. \]

Так как \(X_0=1\), то по индукции

\[ \boxed{ \mathbb E X_n=\mu^n. } \]

TipПроверим формулу методом Монте-Карло

Сгенерируем \(N\) независимых реализаций процесса и вычислим

\[ \widehat{\mathbb E X_n} = \frac1N\sum_{j=1}^N X_n^{(j)}. \]

Сравним это с

\[ \mathbb E X_n=\mu^n. \]

Одновременно посмотрим на медиану \(X_n\).

Show Python code
lam = 1.2
generations = 22
n_paths = 90

paths = simulate_many_poisson(
    lam, n_paths=n_paths, generations=generations, seed=123
)

n = np.arange(generations + 1)
empirical_mean = paths.mean(axis=0)
empirical_median = np.median(paths, axis=0)
theoretical_mean = lam ** n

plt.figure(figsize=(9, 5))
plt.plot(n, theoretical_mean, linewidth=2.5, label=r"Теория: $\mu^n$")
plt.plot(n, empirical_mean, linewidth=2, label="Монте-Карло: среднее")
plt.plot(n, empirical_median, linewidth=2, label="Монте-Карло: медиана")
plt.xlabel("Поколение $n$")
plt.ylabel("Размер поколения")
plt.title(r"Среднее и медиана в надкритическом случае, $\mu=1.2$")
plt.grid(alpha=0.25)
plt.legend()
plt.show()

2 Производящие функции

NoteОпределение

Пусть \(\xi\) — случайная величина. Её производящей функцией называется

\[ G_\xi(z)=\mathbb E z^\xi. \]

Для неотрицательной целочисленной случайной величины

\[ G_\xi(z) = \sum_{k=0}^{\infty} z^k P(\xi=k), \qquad |z|<1. \]

2.1 Основные свойства

  1. \[ G_\xi(1)=1. \]

  2. Если \(\mathbb E\xi<\infty\), то \[ G_\xi'(1)=\mathbb E\xi. \]

  3. Если \(\xi\) и \(\eta\) независимы, то \[ G_{\xi+\eta}(z) = G_\xi(z)G_\eta(z). \]

  4. Для \(\xi\in\mathbb Z_+\): \[ G_\xi(0)=P(\xi=0). \]

  5. Внутри единичного круга производящая функция бесконечно дифференцируема.

  6. Вероятности можно восстановить по производной: \[ P(\xi=k) = \frac1{k!} G_\xi^{(k)}(0). \]

2.2 Производящая функция размера поколения

Пусть \((X_n)_{n\ge0}\) — процесс Гальтона–Ватсона с законом размножения \(\xi\).

CautionЛемма

Для всех \(n\ge0\)

\[ G_{X_{n+1}}(z) = G_{X_n}(G_\xi(z)). \]

Зафиксируем \(m\ge0\). На событии \(\{X_n=m\}\) имеем

\[ X_{n+1} = \sum_{k=1}^{m} \xi_k^{(n+1)}. \]

Поэтому из независимости потомств различных частиц

\[ \mathbb E \left( z^{X_{n+1}} \mid X_n=m \right) = \prod_{k=1}^{m} \mathbb E z^{\xi_k^{(n+1)}} = G_\xi(z)^m. \]

Тогда

\[ \begin{aligned} G_{X_{n+1}}(z) &= \mathbb E z^{X_{n+1}}\\ &= \mathbb E\left[ \mathbb E\left( z^{X_{n+1}} \mid X_n \right) \right]\\ &= \mathbb E\left[ G_\xi(z)^{X_n} \right]\\ &= G_{X_n}(G_\xi(z)). \end{aligned} \]

Поскольку \(X_0=1\), имеем \(G_{X_0}(z)=z\).

Последовательно применяя предыдущую лемму,

\[ G_{X_n}(z) = \underbrace{ G_\xi\circ G_\xi\circ\cdots\circ G_\xi }_{n\text{ раз}} (z). \]

В частности,

\[ \boxed{ G_{X_{n+1}}(z) = G_\xi(G_{X_n}(z)). } \]

3 Вероятность вырождения

Обозначим \(q_n=P(X_n=0)\) — вероятность того, что процесс выродился к моменту \(n\).

Также обозначим \(q=P(\exists n:\ X_n=0)\) — вероятность того, что процесс когда-либо выродится.

Поскольку из \(X_n=0\) следует \(X_{n+1}=0\),

\[ \{X_n=0\}\subseteq\{X_{n+1}=0\}, \]

и поэтому

\[ q_n\le q_{n+1}. \]

По непрерывности вероятностной меры,

\[ \boxed{ q=\lim_{n\to\infty}q_n. } \]

CautionЛемма

Вероятность вырождения \(q\) является решением уравнения

\[ s = G_{\xi}(s). \]

\[ q \leftarrow q_n = \mathbb{P}(X_n=0) = G_{X_n}(0) = G_{\xi}\!\left(G_{X_{n-1}}(0)\right) = G_{\xi}(q_{n-1}) \longrightarrow G_{\xi}(q). \]

TipГеометрия уравнения вырождения

Вероятность вырождения удовлетворяет

\[ q=G_\xi(q). \]

Поэтому нас интересуют точки пересечения

\[ y=G_\xi(s) \qquad\text{и}\qquad y=s. \]

Для пуассоновского закона \(G_\xi(s)=e^{\lambda(s-1)}\).

Сравним

\[ \lambda=0.7,\qquad \lambda=1,\qquad \lambda=1.3. \]

Show Python code
def poisson_extinction_probability(lam):
    if lam <= 1:
        return 1.0
    f = lambda q: np.exp(lam * (q - 1)) - q
    return optimize.brentq(f, 0.0, 1.0 - 1e-12)

fig, axes = plt.subplots(1, 3, figsize=(15, 4.6))
s = np.linspace(0, 1, 700)

for ax, lam in zip(axes, [0.7, 1.0, 1.3]):
    q = poisson_extinction_probability(lam)

    ax.plot(s, poisson_pgf(s, lam), linewidth=2.3, label=r"$\phi(s)$")
    ax.plot(s, s, linestyle="--", linewidth=1.6, label=r"$y=s$")
    ax.scatter([q], [q], s=50, zorder=5, label=rf"$q={q:.3f}$")

    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.set_xlabel("$s$")
    ax.set_title(rf"$\lambda={lam}$")
    ax.grid(alpha=0.25)

axes[0].set_ylabel("$y$")
axes[-1].legend()
plt.suptitle("Геометрия уравнения $s=\\phi(s)$", y=1.02, fontsize=15)
plt.tight_layout()
plt.show()

Вопрос: что делать, если на \([0,1]\) решений несколько?
Т.к. \(\varphi_{\xi}(1)=1\), всегда есть решение \(s=1\).

4 Теорема о вероятности вырождения

Пусть \(\mu=\mathbb E\xi\) и предположим, что

\[ P(\xi=1)\ne1. \]

ImportantТеорема
  1. Если \(\mu\le1\), то уравнение \(s=G_\xi(s)\) имеет на \([0,1]\) единственное решение \(s=1\), и \[ \boxed{q=1.} \]

  2. Если\(\mu>1\), то существует единственный корень \(s_0\in[0,1)\), и \[ \boxed{q=s_0<1.} \]

Иными словами,

\[ \boxed{ q=\min\{s\in[0,1]:G_\xi(s)=s\}. } \]

TipКак последовательность \(q_n\) находит вероятность вырождения?

Мы знаем, что

\[ q_{n+1}=G_\xi(q_n), \qquad q_0=0. \]

Это обычная итерация функции.

Её можно визуализировать с помощью cobweb diagram:

  1. начинаем с \(q_0=0\);
  2. идём вертикально до \(y=G_\xi(s)\);
  3. идём горизонтально до \(y=s\);
  4. повторяем.

Последовательность

\[ q_0,q_1,q_2,\ldots \]

стремится к наименьшей неподвижной точке \(G_\xi\).

Show Python code
lam = 1.5
phi = lambda x: poisson_pgf(x, lam)
q = poisson_extinction_probability(lam)

s = np.linspace(0, 1, 700)

plt.figure(figsize=(7, 7))
plt.plot(s, phi(s), linewidth=2.5, label=r"$y=\phi(s)$")
plt.plot(s, s, linestyle="--", linewidth=1.5, label=r"$y=s$")

x = 0.0
n_steps = 11
for _ in range(n_steps):
    y = phi(x)
    plt.plot([x, x], [x, y], linewidth=1.3)
    plt.plot([x, y], [y, y], linewidth=1.3)
    x = y

plt.scatter([q], [q], s=65, zorder=5, label=rf"$q={q:.4f}$")
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel("$s$")
plt.ylabel("$y$")
plt.title(r"Cobweb diagram для $\xi\sim\mathrm{Pois}(1.5)$")
plt.grid(alpha=0.25)
plt.legend()
plt.show()

5 Фазовый переход: теория против симуляции

Для \(\xi\sim\operatorname{Pois}(\lambda)\) имеем

\[ G(s)=e^{\lambda(s-1)}. \]

Поэтому вероятность вырождения является наименьшим решением

\[ \boxed{ q=e^{\lambda(q-1)}. } \]

Теорема утверждает

\[ q=1,\qquad \lambda\le1, \]

а при \(\lambda>1\)

\[ q<1. \]

TipЧисленный эксперимент

Для каждого \(\lambda\):

  1. найдём теоретическое значение \(q\);
  2. сгенерируем много независимых процессов;
  3. оценим вероятность вырождения методом Монте-Карло.

В надкритическом режиме в численной симуляции процесс будем считать практически выжившим, если его популяция достигла большого порога.

Show Python code
def monte_carlo_extinction_poisson(
    lam,
    n_sim=10,
    max_generations=250,
    survival_threshold=3000,
    seed=0
):
    rng = np.random.default_rng(seed)
    extinct = 0

    for _ in range(n_sim):
        x = 1

        for _ in range(max_generations):

            if x == 0:
                extinct += 1
                break

            if x >= survival_threshold:
                break

            # X_{n+1} | X_n=x ~ Pois(lam * x)
            x = rng.poisson(lam * x)

    return extinct / n_sim


def poisson_extinction_probability(lam):

    if lam <= 1:
        return 1.0

    f = lambda q: np.exp(lam * (q - 1)) - q

    return optimize.brentq(
        f,
        0.0,
        1.0 - 1e-12
    )


# Values of lambda
lambdas = np.linspace(0.3, 2.0, 29)


# Theoretical extinction probability
q_theory = np.array([
    poisson_extinction_probability(lam)
    for lam in lambdas
])


# Monte-Carlo estimate
q_mc = np.array([
    monte_carlo_extinction_poisson(
        lam,
        n_sim=250,
        max_generations=250,
        survival_threshold=3000,
        seed=1000 + i
    )
    for i, lam in enumerate(lambdas)
])


# Plot
plt.figure(figsize=(9, 5))

plt.plot(
    lambdas,
    q_theory,
    linewidth=2.5,
    label="Теория"
)

plt.scatter(
    lambdas,
    q_mc,
    s=30,
    label="Монте-Карло"
)

plt.axvline(
    1,
    linestyle="--",
    linewidth=1.5,
    label=r"Критическая точка $\lambda=1$"
)

plt.xlabel(
    r"$\lambda=\mathrm{E}[\xi]$"
)

plt.ylabel(
    r"Вероятность вырождения $q$"
)

plt.ylim(-0.02, 1.03)

plt.title(
    "Фазовый переход в пуассоновском процессе Гальтона–Ватсона"
)

plt.grid(alpha=0.25)

plt.legend()

plt.show()

6 Достаточно ли знать только среднее число потомков?

Теорема показывает, что

\[ \mu=\mathbb E\xi \]

определяет, происходит ли вырождение с вероятностью \(1\):

\[ \mu\le1 \quad\Longrightarrow\quad q=1. \]

Но при \(\mu>1\) само значение \(\mu\) не определяет \(q\).

Причина в том, что

\[ q=\min\{s\in[0,1]:G_\xi(s)=s\}, \]

а производящая функция зависит от всего закона распределения \(\xi\).

TipОдин и тот же \(\mathbb E\xi\), но разные вероятности вырождения

Возьмём три закона с одинаковым средним

\[ \mathbb E\xi=1.2. \]

Первый:

\[ \xi_1\sim\operatorname{Pois}(1.2). \]

Второй:

\[ \xi_2= \begin{cases} 0,&P=0.4,\\ 2,&P=0.6. \end{cases} \]

Третий:

\[ \xi_3= \begin{cases} 0,&P=0.8,\\ 6,&P=0.2. \end{cases} \]

У них одинаковое среднее, но различные дисперсии и различные производящие функции.

Show Python code
import numpy as np
import matplotlib.pyplot as plt


# ------------------------------------------------------------
# Probability generating functions
# ------------------------------------------------------------

def poisson_pgf(s, lam):
    """
    PGF of a Poisson(lam) random variable:
        phi(s) = exp(lam * (s - 1))
    """
    return np.exp(lam * (s - 1))


def pgf_two_point(s, p0, k):
    """
    PGF for the distribution

        P(xi = 0) = p0,
        P(xi = k) = 1 - p0.
    """
    return p0 + (1 - p0) * s**k


# ------------------------------------------------------------
# Smallest fixed point of phi
# ------------------------------------------------------------

def smallest_fixed_point(phi, eps=1e-12):
    """
    Starting from q_0 = 0, iterate

        q_{n+1} = phi(q_n).

    For a Galton-Watson process this converges to the
    smallest fixed point of phi, i.e. the extinction probability.
    """

    q = 0.0

    for _ in range(100000):

        q_new = float(phi(q))

        if abs(q_new - q) < eps:
            return q_new

        q = q_new

    return q


# ------------------------------------------------------------
# Three offspring distributions with the same mean E[xi] = 1.2
# ------------------------------------------------------------

laws = [
    {
        "name": r"$\mathrm{Pois}(1.2)$",
        "phi": lambda s: poisson_pgf(s, 1.2),
        "mean": 1.2,
        "var": 1.2,
    },

    {
        "name": r"$P(\xi=0)=0.4,\ P(\xi=2)=0.6$",
        "phi": lambda s: pgf_two_point(s, 0.4, 2),
        "mean": 1.2,
        "var": 0.96,
    },

    {
        "name": r"$P(\xi=0)=0.8,\ P(\xi=6)=0.2$",
        "phi": lambda s: pgf_two_point(s, 0.8, 6),
        "mean": 1.2,
        "var": 5.76,
    },
]


# ------------------------------------------------------------
# Compute extinction probabilities
# ------------------------------------------------------------

for law in laws:
    law["q"] = smallest_fixed_point(law["phi"])


# ------------------------------------------------------------
# Plot the PGFs
# ------------------------------------------------------------

s = np.linspace(0, 1, 700)

plt.figure(figsize=(9, 6))

# Diagonal y = s
plt.plot(
    s,
    s,
    linestyle="--",
    linewidth=1.5,
    label=r"$y=s$"
)


# PGFs
for law in laws:

    q = law["q"]

    plt.plot(
        s,
        law["phi"](s),
        linewidth=2,
        label=law["name"] + rf", $q\approx {q:.3f}$"
    )

    # Fixed point
    plt.scatter(
        q,
        q,
        s=50,
        zorder=5
    )


# ------------------------------------------------------------
# Figure formatting
# ------------------------------------------------------------

plt.xlabel(r"$s$")
plt.ylabel(r"$y$")

plt.title(
    r"Одинаковое среднее $\mathrm{E}[\xi]=1.2$, "
    r"но разные вероятности вырождения"
)

plt.xlim(0, 1)
plt.ylim(0, 1)

plt.grid(alpha=0.25)

plt.legend()

plt.show()


# ------------------------------------------------------------
# Numerical results
# ------------------------------------------------------------

print("Сравнение распределений:\n")

for law in laws:

    print(
        f"{law['name']:>38}   "
        f"E[xi] = {law['mean']:.2f},   "
        f"Var(xi) = {law['var']:.2f},   "
        f"q = {law['q']:.4f}"
    )

Сравнение распределений:

                  $\mathrm{Pois}(1.2)$   E[xi] = 1.20,   Var(xi) = 1.20,   q = 0.6863
         $P(\xi=0)=0.4,\ P(\xi=2)=0.6$   E[xi] = 1.20,   Var(xi) = 0.96,   q = 0.6667
         $P(\xi=0)=0.8,\ P(\xi=6)=0.2$   E[xi] = 1.20,   Var(xi) = 5.76,   q = 0.9265

7 Общее число частиц

Обозначим

\[ Y_n=1+X_1+\cdots+X_n \]

— общее число частиц до момента \(n\) включительно.

CautionУтверждение

Производящие функции удовлетворяют рекурсии

\[ G_{Y_{n+1}}(z) = zG_\xi(G_{Y_n}(z)). \]

По определению производящей функции,

\[ G_{Y_n}(z) = \mathbb E\left[z^{Y_n}\right] = \sum_{k=0}^{\infty} \mathbb E\left[ z^{Y_n}\mathbf 1_{\{X_1=k\}} \right]. \]

Зафиксируем событие \(\{X_1=k\}\). Обозначим через \(A_i\) общее число потомков \(i\)-й частицы первого поколения до момента \(n\). Тогда

\[ Y_n = 1+A_1+\cdots+A_k \qquad \text{при условии } X_1=k. \]

При этом

\[ A_i \overset{d}{=} Y_{n-1}, \qquad i=1,\ldots,k, \]

а случайные величины \(A_1,\ldots,A_k\) независимы и не зависят от \(X_1\).

Следовательно,

\[ \begin{aligned} G_{Y_n}(z) &= \sum_{k=0}^{\infty} \mathbb E\left[ z^{1+A_1+\cdots+A_k} \mathbf 1_{\{X_1=k\}} \right] \\[4pt] &= z\sum_{k=0}^{\infty} \mathbb E\left[z^{A_1}\right] \cdots \mathbb E\left[z^{A_k}\right] \mathbb P(X_1=k) \\[4pt] &= z\sum_{k=0}^{\infty} \left[G_{Y_{n-1}}(z)\right]^k \mathbb P(X_1=k) \\[4pt] &= z\,G_{\xi}\!\left(G_{Y_{n-1}}(z)\right). \end{aligned} \]

Таким образом,

\[ \boxed{ G_{Y_n}(z) = z\,G_{\xi}\!\left(G_{Y_{n-1}}(z)\right) }. \]

CautionУтверждение

Пусть \(\mathbb P(\xi=0)\neq 1\). Тогда для всех \(z\in(0,1)\) выполнено

\[ G_{Y_n}(z) < G_{Y_{n-1}}(z), \]

и, значит, существует предел

\[ g(z)=\lim_{n\to\infty}G_{Y_n}(z). \]

Для \(n=1\) имеем

\[ G_{Y_1}(z) = \mathbb E z^{1+X_1} = zG_\xi(z) < z = G_{Y_0}(z). \]

Шаг индукции. Предположим, что

\[ G_{Y_{n-1}}(z)<G_{Y_{n-2}}(z). \]

Тогда, поскольку производящая функция \(G_\xi\) монотонно возрастает,

\[ \begin{aligned} G_{Y_n}(z) &= zG_\xi\!\left(G_{Y_{n-1}}(z)\right) \\ &< zG_\xi\!\left(G_{Y_{n-2}}(z)\right) \\ &= G_{Y_{n-1}}(z). \end{aligned} \]

Следовательно, последовательность \(\{G_{Y_n}(z)\}_{n\geq 0}\) убывает и ограничена снизу нулём, поэтому существует предел

\[ \boxed{ g(z)=\lim_{n\to\infty}G_{Y_n}(z) }. \]

CautionУтверждение

Функция \(g(z)\) удовлетворяет уравнению

\[ \boxed{ g(z)=zG_\xi(g(z)) }. \]

По предыдущему утверждению

\[ G_{Y_n}(z) = zG_\xi\!\left(G_{Y_{n-1}}(z)\right). \]

Переходя к пределу при \(n\to\infty\) и используя непрерывность производящей функции \(G_\xi\), получаем

\[ \lim_{n\to\infty}G_{Y_n}(z) = zG_\xi\!\left( \lim_{n\to\infty}G_{Y_{n-1}}(z) \right). \]

Таким образом,

\[ g(z)=zG_\xi(g(z)). \]

TipНасколько большим может оказаться вымерший процесс?

Даже если

\[ q=1, \]

общее число частиц

\[ Y=\sum_{n=0}^{\infty}X_n \]

может оказаться очень большим.

Особенно интересно приближение к критическому режиму

\[ \mu\uparrow1. \]

Сравним

\[ \mu=0.6,\qquad \mu=0.9,\qquad \mu=0.99. \]

Show Python code
import numpy as np
import matplotlib.pyplot as plt


def simulate_total_progeny_poisson(
    lam,
    n_sim=5000,
    max_generations=10000,
    max_total=2_000_000,
    seed=0
):
    """
    Simulate the total progeny

        Y = X_0 + X_1 + X_2 + ...

    for a Galton-Watson process with Poisson(lam) offspring.

    Since

        X_{n+1} | X_n = x ~ Pois(lam * x),

    we can simulate each generation directly.
    """

    rng = np.random.default_rng(seed)

    totals = np.empty(n_sim, dtype=int)

    for i in range(n_sim):

        x = 1
        total = 1

        for _ in range(max_generations):

            if x == 0:
                break

            # Exact conditional distribution:
            # X_{n+1} | X_n=x ~ Pois(lam * x)
            x = rng.poisson(lam * x)

            total += x

            # Safety cap for extremely large realizations
            if total >= max_total:
                total = max_total
                break

        totals[i] = total

    return totals


def empirical_survival(values):
    """
    Empirical survival function

        P(Y >= y).
    """

    values = np.asarray(values)

    xs, counts = np.unique(values, return_counts=True)

    # Number of observations >= x
    survival_counts = np.cumsum(counts[::-1])[::-1]

    surv = survival_counts / len(values)

    return xs, surv


# ------------------------------------------------------------
# Simulation
# ------------------------------------------------------------

mus = [0.6, 0.9, 0.99]

plt.figure(figsize=(9, 5.5))

for i, mu in enumerate(mus):

    totals = simulate_total_progeny_poisson(
        mu,
        n_sim=7000,
        max_generations=10000,
        max_total=2_000_000,
        seed=500 + i
    )

    x, surv = empirical_survival(totals)

    plt.step(
        x,
        surv,
        where="post",
        linewidth=2,
        label=rf"$\mu={mu}$"
    )


# ------------------------------------------------------------
# Figure formatting
# ------------------------------------------------------------

plt.xscale("log")
plt.yscale("log")

plt.xlabel(r"Общее число частиц $Y$")

plt.ylabel(r"$P(Y\geq y)$")

plt.title(
    "Хвост распределения общего числа частиц"
)

plt.grid(
    alpha=0.25,
    which="both"
)

plt.legend()

plt.show()

8 Время до вырождения

Определим

\[ \boxed{ T=\inf\{n\ge0:X_n=0\}. } \]

Для докритического и критического процессов

\[ P(T<\infty)=1, \]

но распределение \(T\) зависит от близости к критической точке.

TipЧто происходит около критической точки?

Рассмотрим

\[ \xi\sim\operatorname{Pois}(\lambda) \]

при

\[ \lambda=0.5,\quad0.8,\quad0.95,\quad1. \]

Оценим

\[ P(T>n). \]

Несмотря на почти верное вырождение во всех четырёх случаях, около \(\lambda=1\) процесс может существовать очень долго.

Show Python code
def simulate_extinction_times_poisson(
    lam,
    n_sim=10000,
    max_generations=500,
    seed=0
):
    local_rng = np.random.default_rng(seed)
    times = np.full(n_sim, max_generations + 1, dtype=int)

    for i in range(n_sim):
        x = 1
        for n in range(1, max_generations + 1):
            x = int(local_rng.poisson(lam, size=x).sum()) if x > 0 else 0
            if x == 0:
                times[i] = n
                break

    return times

max_n = 120
n_grid = np.arange(max_n + 1)

plt.figure(figsize=(9, 5.5))

for i, lam in enumerate([0.5, 0.8, 0.95, 1.0]):
    T = simulate_extinction_times_poisson(
        lam,
        n_sim=12000,
        max_generations=max_n,
        seed=900 + i
    )
    survival = np.array([(T > n).mean() for n in n_grid])
    plt.plot(n_grid, survival, linewidth=2, label=rf"$\lambda={lam}$")

plt.yscale("log")
plt.xlabel("Поколение $n$")
plt.ylabel(r"$P(T>n)$")
plt.title("Время до вырождения около критической точки")
plt.grid(alpha=0.25, which="both")
plt.legend()
plt.show()

9 Интерпретации и приложения

Несмотря на простоту модели, процессы Гальтона–Ватсона возникают как естественное приближение во многих задачах.

9.1 Эпидемии

На ранней стадии эпидемии один заражённый человек заражает случайное число новых людей.

Если обозначить это число через \(\xi\), то

\[ \mu=\mathbb E\xi \]

играет роль эффективного коэффициента воспроизводства.

При \(\mu<1\) цепочка заражений быстро прекращается, а при \(\mu>1\) существует положительная вероятность большой вспышки.

9.2 Распространение информации в сетях

Каждый пользователь может передать сообщение случайному числу новых пользователей.

На ранней стадии, пока повторные контакты и циклы редки, такая динамика естественно приближается ветвящимся процессом.

9.3 Финансовые каскады

В моделях финансового заражения дефолт одного участника может вызвать дефолты нескольких других участников.

Если сеть разрежена и каскад находится на ранней стадии, число новых дефолтов, вызванных одним дефолтом, можно приближённо описывать законом размножения \(\xi\).

Условие

\[ \mathbb E\xi>1 \]

указывает на возможность самоподдерживающегося каскада.

9.4 Machine Learning и Data Science

Ветвящиеся идеи возникают при изучении:

  • каскадов распространения информации;
  • случайных деревьев;
  • локального исследования разреженных графов;
  • случайных сетей;
  • алгоритмов поиска, порождающих случайное число новых состояний.

Во многих таких моделях процесс Гальтона–Ватсона служит первым приближением локального поведения.