https://github.com/LukaLavs/Generalized-Dual

Uses general dual numbers to compute accurate n-th order partial derivatives of multivariable functions with support for complex numbers, vectorization and arbitrary percision.

https://github.com/LukaLavs/Generalized-Dual

Science Score: 26.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (10.1%) to scientific vocabulary
Last synced: 10 months ago · JSON representation

Repository

Uses general dual numbers to compute accurate n-th order partial derivatives of multivariable functions with support for complex numbers, vectorization and arbitrary percision.

Basic Info
  • Host: GitHub
  • Owner: LukaLavs
  • License: mit
  • Language: Python
  • Default Branch: main
  • Homepage:
  • Size: 815 KB
Statistics
  • Stars: 2
  • Watchers: 0
  • Forks: 0
  • Open Issues: 0
  • Releases: 0
Created about 1 year ago · Last pushed 10 months ago
Metadata Files
Readme

README.md

generalized-dual

A minimal Python library for generalized dual numbers and automatic differentiation, supporting arbitrary-order derivatives, complex numbers, and vectorized operations. Many difficult functions are implemented.

Goal

The goal of this project is to create a simple Python library capable of performing multi-variable, high-order automatic differentiation using generalized dual numbers, while supporting real and complex numbers, vectorized operations, and rich function support.

Installation

This package is available on PyPI. You can install it using pip:

pip install gen-dual

Alternatively, you can install it locally by cloning the repository:

git clone https://github.com/LukaLavs/Generalized-Dual.git
cd generalized_dual
pip install .

Usage

```python from generalizeddual import GeneralizedDual, initialize from generalizeddual.functions import exp, log, sin import numpy as np import mpmath

mpmath.mp.dps = 100 # Set precision

x, y = initialize(np.array([0.5]), np.array([1.0]), m=2) # Prepare variables which support order m derivatives. f = exp(x * y) + log(y) # Define a dual function and evaluate it print(f.diff((1, 0))) # Partial derivative f_x^1y^0 ```


Features

  • Generalized dual numbers for multi-variable, high-order differentiation
  • Real and complex support via mpmath
  • Vectorized NumPy operations
  • Symbolic integration (via Taylor expansions)
  • Rich function support: exp, log, dual_abs, trig, gamma, erfinv, lambertw, and more
  • 📖 See the full list of available functions in FUNCTIONS.md.

Advanced Examples

⚙️ Higher-Order Partial Derivatives

```python from generalized_dual import * import numpy as np import mpmath

mpmath.mp.dps = 50 # Set percision X = np.linspace(0, 3, 5) Y = np.sin(X) Z = np.array([2, 7, 2, 3, 1])

Such choice of X, Y, Z will give us derivatives around points in (X, Y, Z)

x, y, z = initialize(X, Y, Z, m=5) # Set max order of terms to 5, since later we calculate fx^2y1z2 which is of order 5 F = lambertw(x * y - nroot(z, 6)) * log(x, y) Df = F.diff((2, 1, 2)) print("Fx^2yz^2(X, Y, Z) = ") print(Df) ```


🧮 Approximate 2D Integral via Taylor Expansion

```python from generalized_dual import * import numpy as np import mpmath

mpmath.mp.dps = 15 A = [0.3, 0.2] # A = [xmin, ymin] B = [0.7, 0.6] # B = [xmax, ymax] N = [20, 20] # Subdivide x interval into 20 pieces, and same for y interval m = 2 # Approximate with multiple order 2 polinomials around points defined by A;B;N triple integrand = lambda X, Y: sin(X * Y) / beta(X, Y)

Now approximate \int_A^B integrand(x, y) dydx

integralaprox = experimental.integrate(integrand, A, B, N, m) print("Integral approximation: ") print(integralaprox) ```


🔁 Define a Custom Inverse Function via Lagrange Inversion

```python from generalized_dual import * import numpy as np import mpmath

mpmath.mp.dps = 20 def myinversefunc(X): f0, fhat = X.decompose() # Decompose X into dual and non-dual part f0 = np.vectorize(lambda x: mpmath.erfinv(x) if -1 <= x <= 1 else mpmath.nan)(f0) # Apply inverse f on non-dual part X = GeneralizedDual.compose(f0, fhat) # Compose it back x0 = initialize(f0, m=X.m) # Initialize a helper variable F = erf(x0) # evaluate dual f function df = F.derivatives_along(0) # Obtain its derivatives (gives [f^0, f^1, ..., f^m]) return inverse(X, df) # Calls a function which applies Lagrange Inversion Theorem

x = initialize(0.4, m=7) F = myinversefunc(x) print("List of f^0, f^1, ..., f^m:") disp(F.derivatives_along(0)) ```


🔍 Access Specific Taylor Term

```python from generalized_dual import * import numpy as np

X = np.array([[1, 2], [3, 4]]) Y = np.log(X) x, y = initialize(X, Y, m=3) k, l = 2, 1 term = (fresnelc(x - comb(x, y))).terms[(k, l)] print("The term is: ") disp(term) # Term next to (x - x0)^k(y - y0)^l

Note: terms is same size as X and Y variables

```


📈 Plot Mixed Derivative fx²y² with Custom Function

```python from generalized_dual import * import numpy as np import matplotlib.pyplot as plt import time

mpmath.mp.dps = 15 X, Y = np.linspace(0, 2, 200), 2.3 * np.ones(200) x, y = initialize(X, Y, m=4)

F = lambda X, Y: dualabs(lambertw(X) + log(Y)) * exp(-X**2) + \ risingfactorial(sin(X * 5), fresnelc(X * Y) / (X * Y) + 3)

start = time.time() fx2y2 = F(x, y).diff((2, 2), tofloat=True) # tofloat=True converts from mpmath objects into floats for easier graphing end = time.time()

print(f"Execution time for a plot: {end - start:.6f} seconds.")

plt.plot(X, fx2y2, label='∂²f/∂x²∂y² at y=2.3') plt.title('f(x, y) := abs(lambertw(x) + log(y)) + rising_factorial(...)') plt.grid(True) plt.legend() plt.show() ```


🔍 Taylor Approximation of |LambertW(sin(xy + z))| on Branch -1

```python from generalized_dual import * import numpy as np import mpmath import matplotlib.pyplot as plt

X = np.linspace(0, 3, 5) Y, Z = np.sin(X) + 1, np.cos(X) x, y, z = initialize(X, Y, Z, m=3)

F = dualabs(lambertw(sin(x * y + z), branch=-1)) p = 1 # buildtaylor will return an array of functions (same size as X, Y and Z)

With p=1 we will select the function around (x, y, z) = (X[1], Y[1], Z[1])

Xtest = np.linspace(-2 * np.pi, 2 * np.pi, 300) fexact = lambda x: float(mpmath.fabs(mpmath.lambertw(mpmath.sin(x * Y[p] + Z[p]), k=-1))) # Fix y and z variables to get 1-D function Ytrue = np.vectorize(fexact)(X_test)

taylf = buildtaylor(F, X, Y, Z, tofloat=True)[p] Ytaylor = taylf([Xtest, None, None]) # Y and Z variables are fixed. (Fixing variables is not required, but in our case we would get 4-D function or 3-D, which would be hard to plot)

plt.plot(Xtest, Ytrue, label='True') plt.plot(Xtest, Ytaylor, label='Taylor') plt.scatter(X[p], fexact(X[p]), color='red') plt.title(r"$|W{-1}(\sin(xy+z))|$ Taylor Approximation") plt.grid(); plt.legend(); plt.show() ```


✨ Another plot example

```python from generalized_dual import * import numpy as np import matplotlib.pyplot as plt

X = 2 x = initialize(X, m=10)

F = sin(cos(x2) + atan(x)) + sin(4*x) f = lambda x: np.sin(np.cos(x2) + np.arctan(x)) + np.sin(4*x)

taylor = buildtaylor(F, X, tofloat=True) # Since X is not an array, build_taylor just returns a function

Xrange = np.linspace(0, 3, 100) plt.plot(Xrange, f(Xrange), label='func') plt.plot(Xrange, taylor([X_range]), label='taylor') plt.scatter(X, f(X)) plt.ylim(-3, 3) plt.legend() plt.show() ```


🌐 Visualize 2D Taylor Approximation in 3D

```python from generalized_dual import * import numpy as np import matplotlib.pyplot as plt from matplotlib.lines import Line2D

Setup

X, Y = 2, 3 x, y = initialize(X, Y, m=3) # With a goal of plotting taylor polinomial around point (x, y) = (2, 3) F = sin(x * y) # for sin(x y) function f = lambda x, y: np.sin(x * y) # Define a function for plotting the original taylor = buildtaylor(F, X, Y, tofloat=True) # build taylor function around (X, Y)

If X, Y were ndarrays the result would be a ndarray of functions around respected centers

Here build_taylor returned just a function (since X, Y are not arrays)

Grid

xvals = np.linspace(0, 4, 100) yvals = np.linspace(0, 4, 100) Xgrid, Ygrid = np.meshgrid(xvals, yvals)

Evaluate

Zfun = f(Xgrid, Ygrid) Ztaylor = taylor([Xgrid, Ygrid]) # Evaluate taylor polinom around (X, Y)

Note: taylor([X_grid, None]) would return 1-D taylor polinomial of a function f(x, y0=3) around x0=2

Z_point = f(X, Y)

Plot

fig = plt.figure(figsize=(10, 6)) ax = fig.addsubplot(111, projection='3d') ax.plotsurface(Xgrid, Ygrid, Zfun, cmap='viridis', alpha=0.5) ax.plotsurface(Xgrid, Ygrid, Ztaylor, cmap='plasma', alpha=0.5) ax.scatter(X, Y, Zpoint, color='red', s=40)

ax.settitle("Function vs. Taylor Approximation") ax.setxlabel('x'); ax.setylabel('y'); ax.setzlabel('z')

ax.setxlim(1.5, 2.5) ax.setylim(2.5, 3.5) ax.set_zlim(-1, 1)

legendelements = [ Line2D([0], [0], color='blue', lw=3, label='Function'), Line2D([0], [0], color='orange', lw=3, label='Taylor'), Line2D([0], [0], marker='o', color='w', markerfacecolor='red', markersize=8, label='Center') ] ax.legend(handles=legendelements, loc='upper left')

plt.tight_layout() plt.show() ```


Project Structure

generalized_dual/ │ ├── core.py # GeneralizedDual class ├── functions.py # Math operations ├── utils.py # Initialization, display tools ├── experimental/ # Optional features ├── __init__.py tests/ setup.py pyproject.toml README.md LICENSE


📚 References & Further Reading

This project was inspired and guided by the following resources:

If you found additional valuable resources, please consider contributing!

Contributing & Ideas

Contributions, bug reports, and feature suggestions are very welcome!

  • Feel free to submit a pull request or open an issue on GitHub.
  • You can also share ideas, questions, or suggestions via email: lavsluka@gmail.com.

By contributing, you help improve the library and expand its capabilities for the community.


License

MIT © 2025 Luka Lavš

Owner

  • Name: Luka Lavš
  • Login: LukaLavs
  • Kind: user

@&@& @@@ @&& & # && &&& # &@@& @@@ & @ &@& @&@@

GitHub Events

Total
  • Watch event: 3
  • Push event: 6
Last Year
  • Watch event: 3
  • Push event: 6

Dependencies

pyproject.toml pypi
setup.py pypi
  • mpmath *
  • numpy *