mathematicskit.complex_analysis#
The Cauchy-Riemann equations and complex derivatives; contours, contour
integrals (scipy.integrate.quad with complex_func=True),
winding numbers, and Cauchy’s integral formula; residues, the residue
theorem, and the argument principle; conformal maps (Möbius
transformations, the Joukowski map) and mapped coordinate grids; and
domain coloring of complex functions.
mathematicskit.complex_analysis: functions of a complex variable.
The Cauchy-Riemann equations and complex derivatives (central
differences from mathematicskit.calculus); contours, contour
integrals, winding numbers, and Cauchy’s integral formula (via
scipy.integrate.quad() with complex_func=True); Laurent series
via numpy.fft.fft(); residues, the residue theorem, the argument
principle, and Rouché’s theorem; conformal maps (Möbius transformations
and their classification, the Joukowski map) and their action on coordinate
grids; and domain coloring (phase portraits) of complex functions.
- class mathematicskit.complex_analysis.CauchyRiemannResult(u_x, u_y, v_x, v_y)[source]#
Bases:
objectPartial derivatives of \(u = \operatorname{Re} f\) and \(v = \operatorname{Im} f\) at one point.
- class mathematicskit.complex_analysis.Contour(gamma, dgamma, breakpoints)[source]#
Bases:
objectA piecewise-smooth path \(\gamma(t)\) with derivative \(\gamma'(t)\).
gammaanddgammamust accept scalar or arrayt.breakpointsare the sorted parameter values where \(\gamma'\) may jump (a polygon’s corners); the path runs frombreakpoints[0]tobreakpoints[-1]and is smooth on each piece in between.
- class mathematicskit.complex_analysis.DomainColoringResult(z, w, rgb)[source]#
Bases:
objectA sampled complex function \(w = f(z)\) and its domain-coloring image.
- class mathematicskit.complex_analysis.LaurentSeriesResult(center, radius, orders, coefficients)[source]#
Bases:
objectLaurent coefficients \(a_k\) of \(f(z) = \sum_k a_k (z - z_0)^k\) on the circle \(|z - z_0| = r\).
- class mathematicskit.complex_analysis.MappedGrid(horizontal, vertical, horizontal_image, vertical_image)[source]#
Bases:
objectHorizontal and vertical grid lines in the z-plane and their images under a map
f.Each array has one row per grid line.
- Parameters:
- class mathematicskit.complex_analysis.MobiusClassification(kind, trace_squared, fixed_points)[source]#
Bases:
objectThe conjugacy type and fixed points of a Möbius transformation.
- class mathematicskit.complex_analysis.ResidueTheoremResult(integral, poles, residues, winding_numbers, predicted)[source]#
Bases:
objectBoth sides of the residue theorem \(\oint_\gamma f = 2\pi i \sum_k n(\gamma, z_k)\operatorname{Res}(f, z_k)\).
- Parameters:
- mathematicskit.complex_analysis.argument_principle(f, contour, fprime=None, n_points=4000)[source]#
Zeros minus poles of
finsidecontour, \(N - P = \frac{1}{2\pi i}\oint_\gamma \frac{f'(z)}{f(z)}\,dz\).With
fprimethe logarithmic derivative is integrated directly. Without it, \(N - P\) is the winding number of the image curve \(f(\gamma)\) about 0, read off from the unwrapped phase (numpy.unwrap()) of \(f\) sampled along the contour. Both count with multiplicity. See Cauchy (1831, 1855), discussed in F. Smithies, Cauchy and the Creation of Complex Function Theory (Cambridge University Press, 1997), Ch. 6.- Parameters:
- Return type:
- Returns:
int
Examples
>>> from mathematicskit.complex_analysis.systems.contours import circle_contour >>> p = lambda z: z**3 - 0.25 * z # zeros at 0 and +-0.5 >>> argument_principle(p, circle_contour()), argument_principle(p, circle_contour(), fprime=lambda z: 3 * z**2 - 0.25) (3, 3)
- mathematicskit.complex_analysis.cauchy_integral_formula(f, contour, z0, n=0)[source]#
Cauchy’s integral formula \(f^{(n)}(z_0) = \frac{n!}{2\pi i}\oint_\gamma \frac{f(z)}{(z - z_0)^{n+1}}\,dz\).
Recovers the value (
n = 0) or any derivative of a holomorphicfatz0from its values on a contour winding once aroundz0. See A.-L. Cauchy, “Sur la mécanique céleste et sur un nouveau calcul appelé calcul des limites” (Turin, 1831); Ahlfors, Complex Analysis, Ch. 4, Sec. 2.3.- Parameters:
- Return type:
- Returns:
complex
Examples
>>> value = cauchy_integral_formula(np.exp, circle_contour(), 0.3, n=2) >>> round(value.real, 10) == round(float(np.exp(0.3)), 10) True
- mathematicskit.complex_analysis.cauchy_riemann(f, z, h=1e-06)[source]#
The partials \(u_x, u_y, v_x, v_y\) of \(f = u + iv\) at
z.CauchyRiemannResult.residualis (numerically) zero exactly where \(f\) satisfies the Cauchy-Riemann equations.- Parameters:
- Return type:
- Returns:
CauchyRiemannResult
Examples
>>> round(cauchy_riemann(lambda z: z**2, 1 + 2j).residual, 6) 0.0 >>> round(cauchy_riemann(lambda z: z.conjugate(), 1 + 2j).residual, 6) # u_x - v_y = 1 - (-1) 2.0
- mathematicskit.complex_analysis.circle_contour(center=0.0, radius=1.0)[source]#
The counter-clockwise circle \(\gamma(t) = c + r e^{it}\), \(t \in [0, 2\pi]\).
- Parameters:
- Return type:
- Returns:
Contour
Examples
>>> c = circle_contour(1j, 2.0) >>> complex(np.round(c.gamma(0.0), 12)) (2+1j)
- mathematicskit.complex_analysis.classify_mobius(a, b, c, d, atol=1e-12)[source]#
Classify \(T(z) = (az + b)/(cz + d)\) by \(\sigma = (a + d)^2/(ad - bc)\) and find its fixed points.
Conjugate Möbius transformations have the same \(\sigma\), and every non-identity one is conjugate to \(z \mapsto \lambda z\) (two fixed points) or \(z \mapsto z + 1\) (one). The type is elliptic (rotation about the fixed points) for real \(\sigma \in [0, 4)\), parabolic for \(\sigma = 4\), hyperbolic (flow from one fixed point to the other) for real \(\sigma > 4\), and loxodromic (spiral) otherwise. See A. F. Möbius, “Die Theorie der Kreisverwandtschaft in rein geometrischer Darstellung,” Abhandlungen der Königlich Sächsischen Gesellschaft der Wissenschaften 2 (1855), 529-595; Needham, Visual Complex Analysis, Ch. 3, Sec. VI.
- Parameters:
- Return type:
- Returns:
MobiusClassification
Examples
>>> [classify_mobius(*m).kind for m in [(1j, 0, 0, 1), (1, 1, 0, 1), (2, 0, 0, 1), (2j, 0, 0, 1 + 1j)]] ['elliptic', 'parabolic', 'hyperbolic', 'loxodromic'] >>> classify_mobius(0, 1, 1, 0).fixed_points.tolist() # z -> 1/z fixes +-1 [(-1+0j), (1+0j)]
- mathematicskit.complex_analysis.complex_derivative(f, z, h=1e-06)[source]#
\(f'(z) \approx \frac{f(z+h) - f(z-h)}{2h}\), differencing along the real axis.
Only meaningful where
fis holomorphic; check withcauchy_riemann().Examples
>>> d = complex_derivative(lambda z: z**3, 1 + 1j) # 3 z^2 = 6i >>> round(d.real, 6), round(d.imag, 6) (0.0, 6.0)
- mathematicskit.complex_analysis.complex_grid(x_range, y_range, nx, ny=None)[source]#
An
(ny, nx)grid of points \(x + iy\) covering a rectangle.Row
jhas constant imaginary part (a horizontal line), columnkconstant real part (a vertical line), matching theimshowconvention withorigin="lower".- Parameters:
- Return type:
- Returns:
ndarray of complex
Examples
>>> z = complex_grid((-1, 1), (0, 2), 3) >>> z.shape (3, 3) >>> complex(z[0, 0]), complex(z[-1, -1]) ((-1+0j), (1+2j))
- mathematicskit.complex_analysis.contour_integral(f, contour, epsabs=1e-10, epsrel=1e-08, limit=200)[source]#
\(\oint_\gamma f(z)\,dz = \int f(\gamma(t))\,\gamma'(t)\,dt\), via
scipy.integrate.quad().- Parameters:
f (
Callable) –f(z) -> complex, continuous on the contour.contour (
Contour)epsabs (
float) – Tolerances passed toscipy.integrate.quad()for each smooth piece.epsrel (
float) – Tolerances passed toscipy.integrate.quad()for each smooth piece.limit (
int) – Maximum number of adaptive subintervals per piece.
- Return type:
- Returns:
complex
Examples
>>> value = contour_integral(lambda z: 1 / z, circle_contour()) >>> complex(np.round(value, 10)) == complex(0, round(2 * np.pi, 10)) True
- mathematicskit.complex_analysis.domain_coloring(f, x_range=(-2.0, 2.0), y_range=(-2.0, 2.0), resolution=400, saturation=0.9)[source]#
Sample
fon a rectangle and compute its domain-coloring image.- Parameters:
- Return type:
- Returns:
DomainColoringResult
Examples
>>> result = domain_coloring(lambda z: z, (-1, 1), (-1, 1), resolution=5) >>> result.rgb.shape (5, 5, 3) >>> np.round(result.rgb[2, 4], 3).tolist() # w = 1: arg 0 -> red, |w| = 1 -> darkest band [0.7, 0.07, 0.07]
- mathematicskit.complex_analysis.joukowski_map(z, c=1.0)[source]#
The Joukowski map \(J(z) = z + c^2/z\).
It flattens the circle \(|z| = c\) onto the segment \([-2c, 2c]\); a circle through \(z = c\) that encloses \(-c\) maps to an airfoil with a sharp trailing edge. See N. E. Joukowski, “Über die Konturen der Tragflächen der Drachenflieger,” Zeitschrift für Flugtechnik und Motorluftschiffahrt 1 (1910), 281-284.
- Parameters:
- Returns:
complex or ndarray of complex
Examples
>>> w = joukowski_map(np.exp(1j * np.linspace(0, np.pi, 5))) >>> np.round(w, 12).tolist() # 2 cos(theta) [(2+0j), (1.414213562373+0j), 0j, (-1.414213562373+0j), (-2+0j)]
- mathematicskit.complex_analysis.laurent_coefficients(f, z0, radius, n_max, n_points=256)[source]#
Laurent coefficients \(a_{-n}, \ldots, a_n\) of
faboutz0, sampled on \(|z - z_0| = r\).The circle must lie inside the annulus of convergence being studied: the same
fhas different Laurent series on different annuli.- Parameters:
- Return type:
- Returns:
LaurentSeriesResult
Examples
>>> series = laurent_coefficients(lambda z: np.exp(z) / z**2, 0.0, 1.0, 3) >>> [round(series.coefficient(k).real, 10) for k in (-2, -1, 0, 1)] # 1/z^2 + 1/z + 1/2 + z/6 [1.0, 1.0, 0.5, 0.1666666667]
- mathematicskit.complex_analysis.map_grid(f, x_range, y_range, n_lines=11, n_points=200)[source]#
Sample horizontal and vertical grid lines over a rectangle and map them through
f.- Parameters:
- Return type:
- Returns:
MappedGrid
Examples
>>> grid = map_grid(lambda z: 2 * z, (0, 1), (0, 1), n_lines=3, n_points=5) >>> grid.horizontal.shape, complex(grid.vertical_image[-1, -1]) ((3, 5), (2+2j))
- mathematicskit.complex_analysis.mobius_transform(z, a, b, c, d)[source]#
The Möbius transformation \(T(z) = \frac{az + b}{cz + d}\), \(ad - bc \ne 0\).
Möbius transformations are exactly the conformal bijections of the Riemann sphere; they map circles and lines to circles and lines. The Cayley transform \((z - i)/(z + i)\) (
a, b, c, d = 1, -1j, 1, 1j) maps the upper half-plane onto the unit disk.- Parameters:
- Returns:
complex or ndarray of complex
Examples
>>> w = mobius_transform(np.array([1j, 0, 1]), 1, -1j, 1, 1j) # Cayley transform >>> np.round(np.abs(w), 12).tolist() [0.0, 1.0, 1.0]
- mathematicskit.complex_analysis.polygon_contour(vertices)[source]#
The closed polygon through
verticesin order, returning to the first.Side \(k\) is parametrized as \(v_k + (t - k)(v_{k+1} - v_k)\) for \(t \in [k, k+1]\). Listing the vertices counter-clockwise gives a positively oriented contour; clockwise gives winding number \(-1\) about interior points.
- Parameters:
vertices (
Sequence[complex]) – At least three vertices; do not repeat the first at the end.- Return type:
- Returns:
Contour
Examples
>>> square = polygon_contour([0, 1, 1 + 1j, 1j]) >>> complex(square.gamma(2.5)) (0.5+1j)
- mathematicskit.complex_analysis.residue(f, z0, radius=0.01, n_points=256)[source]#
The residue of
fat an isolated singularityz0.- Parameters:
- Return type:
- Returns:
complex
Examples
>>> r = residue(lambda z: np.exp(z) / z**3, 0.0) # coefficient of 1/z is 1/2! >>> bool(np.isclose(r, 0.5)) True
- mathematicskit.complex_analysis.residue_theorem(f, contour, poles, residue_radius=None)[source]#
Compare \(\oint_\gamma f\) with \(2\pi i \sum_k n(\gamma, z_k)\operatorname{Res}(f, z_k)\).
- Parameters:
f (
Callable) – Vectorized and meromorphic, with singularities only atpoles.contour (
Contour) – Closed, not passing through any pole.poles (
Sequence[complex]) – Every singularity off(those outside the contour contribute winding number zero).residue_radius (
float|None) – Radius used byresidue(); defaults to a quarter of the smallest distance between poles, capped at 0.1.
- Return type:
- Returns:
ResidueTheoremResult
Examples
>>> from mathematicskit.complex_analysis.systems.contours import circle_contour >>> f = lambda z: 1 / ((z - 0.5) * (z - 3)) >>> result = residue_theorem(f, circle_contour(), [0.5, 3]) >>> result.winding_numbers.tolist() [1, 0] >>> bool(np.isclose(result.integral, result.predicted)) True
- mathematicskit.complex_analysis.rouche_condition(f, g, contour, n_points=4000)[source]#
Whether \(|f(z) - g(z)| < |g(z)|\) at every sampled point of
contour.By Rouché’s theorem, when this holds, \(f\) and \(g\) have the same number of zeros inside the contour (with multiplicity), so a hard-to-count
fcan be compared with a simple dominant termg. The check is onn_pointssamples, not a proof. See E. Rouché, “Mémoire sur la série de Lagrange,” Journal de l’École Polytechnique 22 (1862), 193-224; Ahlfors, Complex Analysis, Ch. 4, Sec. 5.2.- Parameters:
- Return type:
- Returns:
bool
Examples
>>> from mathematicskit.complex_analysis.systems.contours import circle_contour >>> f = lambda z: z**5 + 3 * z**2 + 1 >>> rouche_condition(f, lambda z: 3 * z**2, circle_contour()), rouche_condition(f, lambda z: z**5, circle_contour(0, 2)) (True, True)
- mathematicskit.complex_analysis.winding_number(contour, z0)[source]#
The winding number \(n(\gamma, z_0) = \frac{1}{2\pi i}\oint_\gamma \frac{dz}{z - z_0}\).
- Parameters:
- Return type:
- Returns:
int – The integral rounded to the nearest integer (it is an integer in exact arithmetic).
Examples
>>> winding_number(circle_contour(), 0.5j), winding_number(circle_contour(), 2.0) (1, 0)