Re: ezunits fundamental_units quite slow
Michael Soegtrop via Maxima-discuss <[email protected]> Sun, 17 May 2026 12:33:12 +0200
| Newsgroups | gmane.comp.mathematics.maxima.general |
|---|---|
| Message-ID | <[email protected]> |
Dear Robert,
looking at the fundamental_units code, I think the fastest way is to use
assoc with conversions_to_base_units and to recurse through the term
structure of the unit term. Not super nice but the version below is
about 70x faster and I believe functionally equivalent.
Btw.: if one would replace " if numberp(expr) then 1" with " if
numberp(expr) then expr" or not recurse on unit results, this would
return the conversion factor as well - which would be a useful variant
for a convert to base units function, but one would need it separately.
And one more note: 95% of the time goes into stripping the numeric
factor. I couldn't find a (much) faster way of doing this. A separate
function applied in the end is 1.5x faster, but that is as far as I got.
But if the number stripping is left away (don't recurse and return
expr), I am at 2000x faster. I believe there must be a fast way to strip
the numeric factor out of results which is faster, but I couldn't find
one (without lisp - even ?cons ?car ?cdr work in Maxima did not help me,
nor did simp:false in the function block). Maybe you have an idea how to
do this.
Best regards,
Michael
/* Recursive tree-walk: expand a unit expression to base units
* using the pre-computed conversions_to_base_units list. */
fundamental_units_rec(expr) := block([r],
if atom(expr) then (
if numberp(expr) then 1
else (
r : assoc(expr, conversions_to_base_units),
if r # false
then fundamental_units_rec(r) /* recurse to strip numeric
factors */
else expr /* base unit: return as-is */
)
)
else if op(expr) = "*" then map('fundamental_units_rec, expr)
else if op(expr) = "^" then fundamental_units_rec(first(expr)) ^
second(expr)
else if op(expr) = "/" then fundamental_units_rec(num(expr)) /
fundamental_units_rec(denom(expr))
else 'fundamental_units(expr) /* unknown form: return noun */
)$
fundamental_units([L]) :=
if L = []
/* No-arg form: return list of base unit symbols [kg, m, s, ...] */
then
map(
lambda([x], r : get(x, 'unit), if r = false then 'unit(x)
else r),
fundamental_dimensions
)
else if listp(L[1])
/* List argument: apply elementwise */
then map('fundamental_units, L[1])
else (
/* Ensure conversions_to_base_units has been computed */
if conversions_to_base_units = 'conversions_to_base_units
then compute_conversions_to_base_units(),
if unitp (L[1])
then
/* Backtick expression like (1`J): strip quantity, expand
unit part */
fundamental_units_rec(units(L[1]))
else
/* Bare unit or compound expression like J, N*m, J/s^2 */
fundamental_units_rec(L[1])
)$
_______________________________________________
Maxima-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/maxima-discuss