Re: Simplifying Units in Ezunits Package
"Mateusz M." <[email protected]> Fri, 8 May 2026 09:42:24 +0200
| Newsgroups | gmane.comp.mathematics.maxima.general |
|---|---|
| Message-ID | <CAOJ_3NG4-LgZzthHTjq07Kkh7CV0Os7csLLC+Y1tiykjVw3z+w@mail.gmail.com> |
Thank you Serge and Robert for answers, I really appreciate it.
> I talked with Claude about this (and gave it access to a Maxima
environment so that it could experiment and look up documentation instead
of working from "memory") and it came up with this helper function
I tried GPT and Gemini PRO before, but those unfortunately failed
hopelessly. It seems that giving the LLM access to the Maxima environment,
as you mentioned, is a way to go.
> Mateusz, I'm glad to hear that Maxima + ezunits are working for you. For
what it's worth, I wrote ezunits hoping that it would be useful for
engineering calculations.
I find it mandatory to have a units package in a engineering tool, because
manually converting units is a simple way to make a mistake. Additionally,
if I make an error somewhere in equations it's clearly visible when units
don't match. Finding it otherwise could be very time consuming. I tried
couple of free and commercial software and selected Maxima as it provides
me with all the required tools for my engineering applications: symbolic
and numerical operations, units, Laplace and inverse Laplace transform,
integrals, derivatives, solving equations (with units!) and many more.
> One approach is to convert different units being added to fundamental
units so they can all be added by the existing rules. Here is a proof of
concept using defrule. This defines a function which can be called to
carry out the operation on any applicable subexpressions via the Maxima
function apply1. (Note that's apply1, not apply.)
This is very interesting, thank you for preparing that.
> I made it a rule that has to be applied explicitly (not automatically)
since it has the potential to make expressions more messy and I'm thinking
the user should choose to do so. This operation is probably important
enough to make it a part of ezunits. Let me think about that.
Personally, I think that would be great and would make it much easier to
work on slightly more challenging examples.
>This is a little confusing to me, I'm not sure what is s here. Is it
supposed to indicate 1 second? If so there is a problem adding resistance
to 1/(time * capacitance), right? Did you mean to say s/C instead of
1/(s*C) ? or something else?
Here "s" stands for complex frequency domain parameter from Laplace
transform. I always use it out of habit, and depending on the analysis I
need to perform, I enter the appropriate value. Here, for example, it's
simply: s = i*2*pi*f, so 1/sC is complex impedance in Ohms.
I tried both methods and they works great! Here is another, slightly more
complicated example of finding sensitivity of function H to one of the
parameters:
H(s, C, R_1, R_2) := (1/(s * C)) / (R_1 + R_2 + 1/(s * C));
diff(H(s, x, R, R), x, 1);
subst(x = C, %);
subst(%i*ω, s, %);
f: subst([R = 1`kOhm, C = 1`nF, ω = 2*%pi*10`Hz], %);
(%i39) /* Serge function */
to_si(f);
dimensionally(cabs(%));
float(%) ``1/microF
(%o37) <some values> ` (kg*m^2)/(A^2*s^4)
(%o38) <some more values> ` (kg*m^2)/(A^2*s^4)
(%o39) 0.12566370415919023 ` 1/microF
(%i44) /* Robert solution */
expr: apply1 (f, rfoo);
fundamental_units (expr);
expr `` %;
dimensionally(cabs(%));
float(%) ``1/microF;
(expr) %i/(20*(2000-(50000000*%i)/%pi)*%pi) `
(A^2*s^3)/(Hz*kg*m^2*nF^2)+-(1/(400*(2000-(50000000*%i)/%pi)^2*%pi^2)) `
(A^4*s^6)/(Hz^2*kg^2*m^4*nF^3)
(%o41) (kg*m^2)/(A^2*s^4)
(%o42) <some values> ` (kg*m^2)/(A^2*s^4)
(%o43) <some more values> ` (kg*m^2)/(A^2*s^4)
(%o44) 0.12566370415919023 ` 1/microF
This example requires prior knowledge of the unit of the result, since the
basic units form (kg*m^2)/(A^2*s^4) isn't very clear (at least to me).
I also tried another example I found difficult: reducing units inside
function calls:
(%i45) func: hstep(1000 ` Hz * 1 ` ms - 1);
(func) hstep(1000 ` Hz*ms-1)
(%i46) /* My suboptimal solution */
subst(Hz = 1/(1000 * ms), func);
(%o46) 1/2
(%i47) /* Serge function */
to_si(func);
(%o47) 1/2
(%i48) /* Robert solution */
apply1 (func, rfoo);
(%o48) hstep(1000 ` Hz*ms-1)
> As you know, this has some drawbacks. How does MathCad handle problems
such as the ones you posed? I will think about ways to try to get similar
behavior. A solution will probably involve some heuristics about how to
find simpler units.
Unfortunately, I no longer have MathCAD installed, but I tried these
examples in SMath and Calcpad (however, I have a problem with calculating
derivative in Calcpad), which are free. I don't know if I can attach
pictures or files here. I may send them to a private mail or host it
somewhere if necessary.
Best regards,
Mateusz
pt., 8 maj 2026, 06:34 użytkownik Robert Dodier <[email protected]>
napisał:
> Mateusz, I'm glad to hear that Maxima + ezunits are working for you.
> For what it's worth, I wrote ezunits hoping that it would be useful
> for engineering calculations.
>
> On Thu, May 7, 2026 at 4:07 AM Mateusz M. <[email protected]> wrote:
>
> > (%o7) (1/10 ` 1/kOhm)/(100 ` pF+10 ` nF) `` 1/s
>
> As you have seen, ezunits doesn't convert different units with the
> same dimensions to a common unit when adding dimensional values.
> (Adding values with the same units is carried out automatically.)
>
> One approach is to convert different units being added to fundamental
> units so they can all be added by the existing rules. Here is a proof
> of concept using defrule. This defines a function which can be called
> to carry out the operation on any applicable subexpressions via the
> Maxima function apply1. (Note that's apply1, not apply.)
>
> defrule (rfoo, aa + uu%, add_with_units_try_harder (aa, uu%));
> add_with_units_try_harder (x%, u%) :=
> if op(u%) = "+"
> then (if length (unique (map (second, u%))) = 1 then
> add_with_units (x%, u%) else add_with_units (x%,u% ``
> fundamental_units (first (u%))))
> else x% + u%;
>
> For the expression above, I get:
>
> expr1: (1/10 ` 1/kOhm)/(100 ` pF+10 ` nF);
> expr2: apply1 (expr1, rfoo);
> => 1000000000/101 ` (kg*m^2)/(A^2*kOhm*s^4)
> fundamental_units (expr2);
> => 1/s
> expr2 `` 1/s;
> => 1000000/101 ` 1/s
>
> I made it a rule that has to be applied explicitly (not automatically)
> since it has the potential to make expressions more messy and I'm
> thinking the user should choose to do so.
>
> This operation is probably important enough to make it a part of
> ezunits. Let me think about that.
>
> > (%i15) H(s, C, R_1, R_2) := (1/(s * C)) / (R_1 + R_2 + 1/(s * C));
>
> This is a little confusing to me, I'm not sure what is s here. Is it
> supposed to indicate 1 second? If so there is a problem adding
> resistance to 1/(time * capacitance), right? Did you mean to say s/C
> instead of 1/(s*C) ? or something else?
>
> Anyway I find that if I say
>
> expr3: H(1`Hz, 18`nF, 1`kOhm, 1`kOhm);
> => (1/18 ` 1/(Hz*nF))/(2 ` kOhm+1/18 ` 1/(Hz*nF))
>
> and then I can use rfoo again,
>
> expr4: apply1 (expr3, rfoo);
> => 1/1000036000 ` (A^2*s^3)/(Hz*kg*m^2*nF)
>
> and then
>
> fundamental_units (expr4);
> => 1
> expr4 `` 1;
> => 250000/250009
>
> I don't know if that's really valid, since it depends on calling H
> with s = 1 ` Hz.
>
>
> > Is there perhaps a simple and universal way to simplify units like in
> MathCad or other engineering tools?
>
> Well, simplifying units is a bit tricky since what's "simpler" depends
> on the context to some extent. ezunits doesn't automatically convert
> units, as you have seen, instead letting the units be whatever the
> user wrote.
>
> As you know, this has some drawbacks. How does MathCad handle problems
> such as the ones you posed? I will think about ways to try to get
> similar behavior. A solution will probably involve some heuristics
> about how to find simpler units.
>
> Hope this helps,
>
> Robert
>
_______________________________________________
Maxima-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/maxima-discuss
1000001878.png
(image/png, 23.4 KB) - not displayed