On Wed, Jul 05, 2023 at 12:51:55AM +0200, Ralf Hemmecke wrote:
> Dear Waldek,
>
> Thank you for your explanation. It's always hard to find the right functions
> if one doesn't know it already.
>
> I am always getting so frustrated when it comes to Expression(...).
> I know one can do a lot of things with and within the Expression domain, but
> I find it hard and cumbersome to take things apart to achieve what I want.
> Actually, I fear that I am not alone with this issue.
>
> Clearly, it is even hard to give a good name to a function that does exactly
> what I want. And then this function would have to check that the expression
> it gets as input has a certain format.
>
> It's already difficult (or even impossible) to convert my s2 into
> AlgebraicNumber.
Well, the trouble is %i, if you use sqrt(-1), then you will
get Expression(Integer) and things will be easy. But one can
do
(6) -> eI := Expression(Integer)
(6) Expression(Integer)
Type: Type
(7) -> eCI := Expression(Complex(Integer))
(7) Expression(Complex(Integer))
Type: Type
(8) -> iTM := ITRIGMNP(Integer, eI, eCI)
(8)
InnerTrigonometricManipulations(Integer,Expression(Integer),Expression(Comple
x(Integer)))
Type: Type
(9) -> FG2F(r1)$iTM
+------------------------------------------------------------+
| +---+ +--+
(9) \|1097675101059710976000 \|- 1 \|67 + 36223278334970462208000
Type: Expression(Integer)
(10) -> %::AlgebraicNumber
+------------------------------------------------------------+
| +---+ +--+
(10) \|1097675101059710976000 \|- 1 \|67 + 36223278334970462208000
Type: AlgebraicNumber
How one knows the name 'FG2F'? The answer unfortunetly seem to
be "read the source". It is used by integrator: first F2FG
convert form Expression(Integer) to Expression(Complex(Integer)),
then main work is done over complex numbers and then F2FG converts
result back to Expression(Integer)...
How one could write function like 'FG2F'? That is actually resonably
easy: over integral domains expression is just rational function in
kernels. So it is enough to separately transform numerator and
denominator, which is polynomial maniputation. For polynomials
we have PolynomialCategoryLifting which allows relatively simple
definition for complex transformation. You just need to define
map on coefficients and on variables. On coefficient our map
is easy, we map z to real(z) + sqrt(-1)*imag(z). More complex
is map on variables, that is kernels. We need to extract operator
and arguments from the kernel, for operator in
Expression(Complex(Integer)) we need to find its equvalent in
Expression(Integer), this is done by 'operator' function form
Expression(Integer), so we have silly looking code like
new_op := operator(operator(k))$Expression(Complex(Integer))
Once we have new operator you recusively transform arguments and apply
operator to transformed arguments.
If you think a bit that is acutally quite general scheme for building
transformations: if you want transformation to be a homomorphism,
which is natural requirement, then you need to define map on
coefficient and on kernes. If you leave coefficients alone,
there is utility function 'rmap' in ElementaryFunctionStructurePackage
which takes map from kernels to expressions and lifts it to
map on expressions.
What about rewrite rule that I used in another post? This is
build differently then recipe above and in general is dangerous.
I the example it was fine, but such rewirite rule can lead to
depenedent roots which may cause troubles (some years ago I
presented short "0 = 1" proof based on FriCAS handing of
dependent roots).
There is another kind of problems not handled by recipe above:
one can ask if an expression is in some specific subset.
Typical FriCAS pattern here uses 'univariate' reducing
problem to univariate polynomias or ratinal functions having
expressions as coefficients. But there are natural problem
whicj I do not know how to handle by 'univariate' pattern.
One of then is: given expression a and expressions b1,...,bn
check if a is in the field generated by b1,...,bn and in
case of positve anwer write a as rational function of b1,...,bn.
I think that this is solvable using Groebner bases, but probably
does not have signifcantly simpler solution.
> Maybe I must study Expression even more. But we certainly need more examples
> of how to convert from Expression to some more specific domains. This is
> what I am currently lacking.
There are retractions to kernels, coefficients, symbols and polynomials.
You can retract Expression(Integer) to AlgebraicNumber.
'numer', 'denom' and 'univariate' give you way to disassemble
expressions. You can decompose kernel into operator and arguments.
This allows you to build various transformations. There are
predefined functions for "typical" cases.
To get some ideas it may be worthwile to read 'efstruc.spad' and
'manip.spad'.
You can also use pattern matching, but this is a "convenience
feature", FriCAS pattern matching is build on top of operations I
mentioned above.
--
Waldek Hebisch