From 68c065f295864433063e153baf70b68e0fa7b0f1 Mon Sep 17 00:00:00 2001 From: AlexKurek Date: Sat, 2 May 2026 08:23:08 +0200 Subject: [PATCH 1/3] Make `gaus_2d` faster (2) --- bdsf/functions.py | 54 ++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/bdsf/functions.py b/bdsf/functions.py index 7806e0c..9293e1b 100644 --- a/bdsf/functions.py +++ b/bdsf/functions.py @@ -205,32 +205,48 @@ def gaus_2d(c, x, y): import math import numpy as N - # Pre-calculate rotation parameters outside of matrix operations - rad = 180.0/math.pi - angle_rad = c[5]/rad + # Scalar calculations (executed only once) + rad = 180.0 / math.pi + angle_rad = c[5] / rad cs = math.cos(angle_rad) sn = math.sin(angle_rad) - # Coordinate shift - dx = x - c[1] - dy = y - c[2] + # Faster at the C level than c[3]**2 + inv_sigx2 = 0.5 / (c[3] * c[3]) + inv_sigy2 = 0.5 / (c[4] * c[4]) - # Avoiding the creation of unnecessary temporary arrays. The original function divided - # values before squaring, which created additional matrix copies in memory. The new - # version multiplies by the inverse of the square, which is a more computationally - # efficient. - inv_sigx2 = -0.5 / (c[3]**2) - inv_sigy2 = -0.5 / (c[4]**2) + cs2 = cs * cs + sn2 = sn * sn + sn_cs_2 = 2.0 * sn * cs - # (f1^2 + f2^2) can be expressed as a quadratic form, which is computed faster by NumPy - # f1 = (dx*cs + dy*sn) / sigx - # f2 = (dy*cs - dx*sn) / sigy - f1_part = dx * cs + dy * sn - f2_part = dy * cs - dx * sn + # Components of the expanded ellipse equation (already negated) + # Calculated as scalars, so they take no time + A_neg = -(cs2 * inv_sigx2 + sn2 * inv_sigy2) + B_neg = -(sn2 * inv_sigx2 + cs2 * inv_sigy2) + C_neg = -(sn_cs_2 * (inv_sigx2 - inv_sigy2)) - exponent = (f1_part**2 * inv_sigx2) + (f2_part**2 * inv_sigy2) + # Create result arrays. Instead of inheriting the type from x and y + # (which could be int), force float by * 1.0 + dx = (x - c[1]) * 1.0 + dy = (y - c[2]) * 1.0 - return c[0] * N.exp(exponent) + exponent = dx * dy + exponent *= C_neg # in place + + # In place to avoid allocating new RAM + dx **= 2 + dx *= A_neg + exponent += dx + + dy **= 2 + dy *= B_neg + exponent += dy + + # Overwrite the exponent array with the results of the exp() function + N.exp(exponent, out=exponent) + + exponent *= c[0] + return exponent def gaus_2d_itscomplicated(c, x, y, p_tofix, ind): """ x and y are 2d arrays with the x and y positions. c is a list (of lists) of gaussian parameters to fit, p_tofix From 291f1e00ae6bde0b5e766661185df585ec3ee2d6 Mon Sep 17 00:00:00 2001 From: AlexKurek Date: Sat, 2 May 2026 08:47:42 +0200 Subject: [PATCH 2/3] Add micro optimisations --- bdsf/functions.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/bdsf/functions.py b/bdsf/functions.py index 9293e1b..069b793 100644 --- a/bdsf/functions.py +++ b/bdsf/functions.py @@ -227,25 +227,30 @@ def gaus_2d(c, x, y): # Create result arrays. Instead of inheriting the type from x and y # (which could be int), force float by * 1.0 - dx = (x - c[1]) * 1.0 - dy = (y - c[2]) * 1.0 + # Force a copy in float and subtrac in place to avoid creation + # of temporary array for (x - c[1]) + dx = N.array(x, dtype=N.float64, copy=True) + dx -= c[1] + + dy = N.array(y, dtype=N.float64, copy=True) + dy -= c[2] + # In place to avoid allocating new RAM exponent = dx * dy - exponent *= C_neg # in place + exponent *= C_neg - # In place to avoid allocating new RAM - dx **= 2 - dx *= A_neg - exponent += dx + dx *= dx + dx *= A_neg + exponent += dx - dy **= 2 - dy *= B_neg - exponent += dy + dy *= dy + dy *= B_neg + exponent += dy # Overwrite the exponent array with the results of the exp() function N.exp(exponent, out=exponent) - exponent *= c[0] + return exponent def gaus_2d_itscomplicated(c, x, y, p_tofix, ind): From 4068fe27c9920a3ab1f8abc018e7c3d3cc0f2f74 Mon Sep 17 00:00:00 2001 From: AlexKurek Date: Sat, 2 May 2026 11:42:15 +0200 Subject: [PATCH 3/3] Remove unnecessary whitespaces --- bdsf/functions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bdsf/functions.py b/bdsf/functions.py index 069b793..8d0385b 100644 --- a/bdsf/functions.py +++ b/bdsf/functions.py @@ -239,13 +239,13 @@ def gaus_2d(c, x, y): exponent = dx * dy exponent *= C_neg - dx *= dx - dx *= A_neg - exponent += dx + dx *= dx + dx *= A_neg + exponent += dx - dy *= dy - dy *= B_neg - exponent += dy + dy *= dy + dy *= B_neg + exponent += dy # Overwrite the exponent array with the results of the exp() function N.exp(exponent, out=exponent)