to_poly_solve results are hard to handle programmatically mostly because it handles many more cases correctly and completely, notably periodic functions. I agree that the form of its results can appear complicated and so be off-putting -- can we find a simpler way of expressing the same semantics? For example, we should be able to replace isnonnegative_p(x) with x>=0?
This is an interesting one. Although csc(x) and cot(x) are undefined at x=0, csc(x)-cot(x) is 0 by analytic continuation at x=0. Maxima generally ignores isolated singularities like this, for example it simplifies x/x to 1. So it's unclear whether this is a bug. BTW, %solve(csc(x)-cot(x),x) => %union([x = 2 %pi %z874])
Lisp didn't have multiple value returns when I wrote risplit (1971 or so), and memory was considered expensive, hence the dotted pair. Multiple values seem like the right way to do it today, and are even more efficient! Also, dotted pairs of Maxima expressions don't print very nicely.
Internal code should be using risplit (the other bug report). Not sure why Lisp code would be calling $num/$denom, which as you point out are expensive because they first format the expression. But of course both of these are possible, just as it's possible that Lisp code isn't following other conventions like always returning simplified expressions. I suppose that you have been cleaning up a lot of these taking advantage of Claude.
Of course Maxima bindings matter, but can Lisp-level let etc. affect Maxima-level calls? Maybe in ev?
A simple approach to safe caching is to increment a global-state counter. Any side-effect operation -- assignment to a global variable (not just flags), redefinition of a function, declaration or assumption, etc. -- would increment the counter. I suspect that in the vast majority of cases, that would save a recalculation. Is it worth it? Not sure. But with the help of Claude, I'd think it would be pretty easy to replace all instances of (setq $xxx ...) with (gsetq $xxx ...) etc. where gsetq takes...
That isn't supported in 5.49. But maybe it's in a more recent version? -- I need to update to 5.50 I guess. block([[n,d]:[4,5]],n+d); Only symbols can be bound; found: [n,d]
I agree that pairs of functions like num/denom, realpart/imagpart, etc. are often used together and are computationally wasteful. However, I think they're more compact, easier to write, and clearer than something like block([numdem: num_denom(x)], if oddp(numdem[2]) then abs(numdem[1])/numdem[2]) ... or block([numdem: num_denom(x), num, denom], num: numdem[1], denom: numdem[2], if oddp(denom) then abs(num)/denom) ... versus if oddp(denom(x)) then abs(num(x))/denom(x) So rather than add a num_denom...