Open asmeurer opened 2 years ago
In some situations it's more useful to be able to say "give me any local inverse" rather than a full inverse.
Where a full inverse is needed it might be more useful to have a preimage
function i.e. something that answers the question: what is the set of values for x such that f(x) = y
(with y being a single value rather than a set)?
In some situations it's more useful to be able to say "give me any local inverse" rather than a full inverse.
If you just want one such example you can use next(iter(expr.inverse_set()))
, e.g.,
>>> next(iter(ImageSet(Lambda(n, asin(y) + n*pi), Integers)))
asin(y)
(or the take
helper).
Where a full inverse is needed it might be more useful to have a preimage function i.e. something that answers the question: what is the set of values for x such that f(x) = y (with y being a single value rather than a set)?
Maybe I'm misunderstanding what you're suggesting here, but wouldn't this be the same as my suggested inverse_set? I'm OK with using preimage
instead as a more mathematically correct name. I suggested inverse_set
in analogy with the already existing inverse
.
The main point here is there needs to be a way for functions to fully define their behavior for solve
/solveset
. Currently only one-to-one functions can.
If you just want one such example you can use
next(iter(expr.inverse_set()))
, e.g.,
I expect that there are many situations where that might fail or might do the wrong thing. It's much better to have a clear way to say "just give me any inverse and don't waste time computing anything more difficult or complicated than that".
Maybe I'm misunderstanding what you're suggesting here, but wouldn't this be the same as my suggested inverse_set?
Actually yes but maybe rename the "symbol" argument. The idea is that it is really a value so that we are computing the preimage for a particular element rather than returning an inverse "function".
I expect that there are many situations where that might fail or might do the wrong thing. It's much better to have a clear way to say "just give me any inverse and don't waste time computing anything more difficult or complicated than that".
I'd say this falls into the more general category of helpers to convert sets and results from solveset into useful expressions, including into the sort of answer that solve
might return. The set itself is the most general answer and should, in principle, contain enough information to compute this. That might depend on representing the set in a convenient way, but that's not a big problem (e.g., if an ImageSet is easier to iterate over than a ConditionSet then we should try to represent the solution set as an ImageSet).
So really, I think the focus should be on improving the ability to compute things on sets and simplify set expressions. If we do that, then we can work with the general solutions while still being able to extract useful expressions from them.
Another thing I forgot to mention is that much like fdiff, the result should be independent of the actual args of the function. Recursive solving is a problem for solve. Maybe it would make sense to make this a classmethod to emphasize that?
I'd say this falls into the more general category of helpers to convert sets and results from solveset into useful expressions
No, I don't think it does because I don't even want solveset et al to bother computing the things that they compute just so that I can extract a tiny subset of that afterwards.
Right now, classes can define an
inverse
method to return an inverse function. This tellssolve
andsolveset
how to invert the function. It works likeThe problem is that because it returns a single function object, it only really works for one-to-one functions (left inverse). Functions that are multivalued can't return a single inverse function. Some multivalued functions have inverse defined anyway (like
exp
) and some do not (likesin
).I propose generalizing this with a new method
inverse_set
. It would look like(see https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Solutions_to_elementary_trigonometric_equations).
solveset
would then use this to solve expressions containingsin
(for known functions likesin
, it may also use other algorithms and rewrites in addition to this). For instance,solveset(sin(x) - y, x)
would be equivalent tosin(x).inverse(y)
(n.b. solveset currently can't handle this equation). We could also define a generalinverse_set
on theFunction
base class that returns a ConditionSet, although it might only be convenient for end-users of the method.For
solve
to make use ofinverse_set
, we would need to implement more general translation fromsolveset
tosolve
, which needs to be done anyway.Note that
inverse_set
would primarily only be defined onFunction
subclasses. The logic insolveset
would still be needed to invert the functions inside of larger expressions.It may make more sense for it to be method that starts with an underscore, like
_eval_inverse_set
, so that users aren't encouraged to use it directly. Although this is a much more end-user friendly API since it would return an actual expression rather than a callable function.