Need built-in function for n'th root
The semantics of a ^ b with separation of Real and Integer exponents is a good start for also specifying unit semantics of exponentiation. However, for the inverse operation of taking roots, the language only has sqrt to offer.
I suggest that we introduce the nthRoot function now as I can see the need coming when we get to standardization of unit checking.
Here's a sketch of semantics to show in some more detail what this is all about:
-
nthRoot(a, b)takes aReal a, anInteger b, and produces aRealresult. - It is an error for
bto be zero. - For
b < 0, the result is defined as1 / nthRoot(a, -b) - If
bis even, it is required thata >= 0, and the result is they >= 0such thaty ^ b = a. - If
bis odd, and the result is theysuch thaty ^ b = a(ywill have same sign asa).
If the idea is of interest, I suggest that further discussions of detailed semantics should be made in a PR rather than in this issue.
However, Modelica is equation-based!
And in equations we can generally replace nthRoot(x, n) = a; by a^n = x; and tools can then symbolically solve that - which involves the nthRoot in most cases.
Thus I'm not convinced that we need this.
Some reasons against relying on equations:
- The equation rewrite is likely to blur the purpose of the code when eliminating an n'th root in the middle of a bigger expression/equation.
- The equation requires an auxiliary variable to be introduced, and it may not even be possible to express the
unitof that variable due to rational exponents in the units. - The equation solution can't be used to define a
nthRootfunction in user code. - The equation solution doesn't give any guarantees on which root to get.
Phone meeting: Better name! Maple has: root(x, n) (risk of ambiguity with user models). surd in Wolfram (hard to understand).
Thus nthRoot has some advantages compared to these.
Would be good with more convincing examples (might be related to unit-checking). Should fail on even roots of negative numbers.
After some investigation I found that surd isn't the right term for this, as it seems √8 is a surd - but ∛8 isn't a surd; basically it refers to irrational numbers formed using roots; which is important in symbolic math packages (as they are normally kept in that form).
Would be good with more convincing examples (might be related to unit-checking).
How about a MultiBody ball parameterized by mass and density?
In case we need more name alternatives: reciprocalPower. (I still prefer nthRoot, just trying to get some progress here.)
Here are some more examples of what the (essentially same) function is called in other software:
- Sage:
real_nth_root - SymPy mpmath:
rootornthroot - SymPy.simplify:
nthroot - Julia IntervalArithmetic:
nthroot
To summarize, I think nthRoot would be a rather well recognized name from start.
To summarize, I think
nthRootwould be a rather well recognized name from start.
And we already have some operators using that style (lower camel case) for noEvent, ticksInState etc.
In some world combing it with sqrt by having root(x, n=2) would have made sense, but based on the current spec and other languages it is too distracting without any major benefit.
How about a MultiBody ball parameterized by mass and density?
Computing cube-roots in general seems relevant, in particular since the obvious x^(1/3) will fail for negative numbers.
Following C (and C++) and merely adding cbrtl for cube roots would be less clear.
However, in the specific case I would normally write something like parameter Real mass=...;parameter Real density=...;protected parameter Real r(fixed=false);parameter Real computedMass=4*pi*density*r^3/3;initial equation mass=computedMass; since that formula is somewhat well-known.
Understanding that r=nthRoot(0.75*mass/(density*pi), 3) is the same requires some comments.
(BTW: I don't think we need to consider other fractional powers like x^(2/3) - both since it is less common, and also because nthRoot(x,3)^2 should just work. However, it is still relevant for units.)
(BTW: I don't think we need to consider other fractional powers like
x^(2/3)- both since it is less common, and also becausenthRoot(x,3)^2should just work. However, it is still relevant for units.)
Yes, and a good reason to avoid an operator like pow(x, num = 3, den = 2) is that one would be tempted to also overload it with pow(x, 1.5), but the overloaded semantics are actually so unrelated that it is just confusing to use the same overloaded operator. Also, rationalPow(x, num = 1, den = 3) seems like a cumbersome way to express nthRoot(x, 3). Finally, I find it more natural to specify semantics for negative x in nthRoot(x, 3) than for rationalPow(x, num = 1, den = 3).
Looking through MSL I actually noticed that x^(2/3) is currently used - in Modelica.Fluid.Vessels.ClosedVolume to compute the area based on volume. (And in Modelica.Media.IdealGases.Common.Functions.dynamicViscosityLowPressure for something)
Good! Are we ready to go ahead with nthRoot then?
Why does this need to be a built-in function? Would it not be better to put it in the standard library?
It is not possible to make a user-defined function with special unit semantics for constant Integer arguments.
Phone meeting: Agreement to go with nthRoot.