On Thu, Jul 20, 2023 at 01:29:10PM +0000, '68th' via FriCAS - computer algebra 
system wrote:
> ------- Original Message -------
> On Wednesday, July 19th, 2023 at 4:46 PM, Ralf Hemmecke <r...@hemmecke.org> 
> wrote:
> 
> > Ah, you want to challenge me. ;-) No, honestly, I am grateful that you
> > pose such questions.
> 
> No, I don't want to challenge anybody. I just want to know how to get in 
> FriCAS what I want. I think it will be easier to achieve it with an example.
> 
> > (323) -> eq := c^2 = a^2 + b^2 -(2ab)*cos(gamma)
> 
> The reason why I enclosed 2ab in brackets is to visually separate it from 
> cosine. Otherwise one could think there are six variables: a, b, c, o, s, and 
> γ. That's not what I want FriCAS to distribute.
>  
> > (324) -> map(x +-> subst(x,[a=(l+k)/2, b=(l-k)/2]), eq)
> 

Fixing syntax and naming results for easier reference:

(5) -> eq1 := c^2 = a^2 + b^2 -(2*a*b)*cos(gamma)

         2                         2    2
   (5)  c  = - 2 a b cos(gamma) + b  + a
                                          Type: Equation(Expression(Integer))
(6) -> eq2 := map(x +-> subst(x,[a=(l+k)/2, b=(l-k)/2]), eq)

                 2    2               2    2
         2   (- l  + k )cos(gamma) + l  + k
   (6)  c  = -------------------------------
                            2
                                          Type: Equation(Expression(Integer))

> 
> That's just a preliminary step. Now we get to the point. How to distribute 
> cos(γ) over (k²-l²) and then factor out k² and l² to derive 
> k²(1+cos(γ))+l²(1-cos(γ))?

Well, see (adding divisions by 2 that you skipped):

(9) -> k^2*(1+cos(gamma))/2 + l^2*(1-cos(gamma))/2

            2    2               2    2
        (- l  + k )cos(gamma) + l  + k
   (9)  -------------------------------
                       2
                                                    Type: Expression(Integer)

So this is what we have above.  To be really sure you can do:

(10) -> rhs(eq2) - %

   (10)  0
                                                    Type: Expression(Integer)

We got zero, so the two things are equal (just in case: % above means
previous result).

This is prefered style of calculations in FriCAS.  In particular
in many textbook algorithms there are tests for zero.  If your
expression is properly preprared (your input is simple happy case
that needs no preparation), then checking for zero is as
easy as above: you just look if result printed as zero.  Systems
"keep form" of expression have trouble with zero test: either
system automatically simplifies expressions to 0, so does not
"keep form" of zero, or you need special test for zero.  FriCAS
normally (as I mentioned, each FriCAS type can use it own rules)
tries keep values is so called normal form, that is form where
zero is clearly visible.  For example

(24) -> a := (sqrt(x^2 + 1) + 1)/x

          +------+
          | 2
         \|x  + 1  + 1
   (24)  -------------
               x
                                                    Type: Expression(Integer)
(25) -> b := x/(sqrt(x^2 + 1) - 1)

               x
   (25)  -------------
          +------+
          | 2
         \|x  + 1  - 1
                                                    Type: Expression(Integer)
(26) -> a - b                     

   (26)  0
                                                    Type: Expression(Integer)

a and b look different, but subtraction shows that they are equal.

There are more complicated cases like

(27) -> sin(x)^2 + cos(x)^2 - 1

               2         2
   (27)  sin(x)  + cos(x)  - 1
                                                    Type: Expression(Integer)

This does not simplify in automatic way.  But 'normalize' discovers
that is is zero:

(28) -> normalize(%)

   (28)  0
                                                    Type: Expression(Integer)

Note: ATM 'normalize' gives you reliable 0 test for trigonometic or
exponential functions.  But if you add logarithms or inverse
trigonometric functions things get more complicated.  And 'normalize'
is weaker than it should when handling algebraic functions.

Anyway, if you want the check that result of calculation is zero,
you should nomalize all inputs to your calculation, do the calculation
and see if it is zero.   Intermatiate results form normalize may
look ugly and complicated, but this is powerful simplifcation
when you want to compute with something.

Coming back to your question, you can create expressions that
look the way you want.  First, I am not sure what you want to
do with division by 2.  So I simplify the expression by multiplying
it by 2:

(33) -> re := 2*rhs(eq2)

             2    2               2    2
   (33)  (- l  + k )cos(gamma) + l  + k
                                                    Type: Expression(Integer)

Then we need list of kernels:

(34) -> lk := kernels(re)

   (34)  [cos(gamma), l, k]
                                      Type: List(Kernel(Expression(Integer)))
We extract one of kernels, say l:

(36) -> ker_l := lk(2)

   (36)  l
                                            Type: Kernel(Expression(Integer))

Then 'univariate' separates expression with respect to powers of l
(but for printing l is replaced by ?):

(37) -> univariate(re, ker_l)

                            2    2              2
   (37)  (- cos(gamma) + 1)?  + k cos(gamma) + k
              Type: Fraction(SparseUnivariatePolynomial(Expression(Integer)))

To make things simple we extract numerator from the above (denominator
is 1 and isn not printed):

(38) -> nu := numer(%)                                   

                            2    2              2
   (38)  (- cos(gamma) + 1)?  + k cos(gamma) + k
                        Type: SparseUnivariatePolynomial(Expression(Integer))

Now we can collect things back, but prevention them from normal
simplification rules:

(40) -> box(l^2*coefficient(nu, 2)) + box(coefficient(nu, 0))

          2              2      2              2
   (40)  k cos(gamma) + k  + - l cos(gamma) + l
                                                    Type: Expression(Integer)

Note there is a glitch there: '-' before l^2 is inside box, '+' before
that is '+' between boxes.   This is very general technique: using
'kernels', 'univariate', 'numer', 'donom' and possibly recursing
on kernels using 'operator' and 'argument' your routine can dissect
expression and transform it in any desirable way.  For results you
can use 'box' or 'paren', or if only printing is involved you
could produce an OutputForm.  Note: that still does not control
order of printouts, one would have to do slightly more.

Of course, it would be very tedious to perform such commands like
above by hand.  But the nomal approach is that once you find
short sequence of commands doung part of needed tranformation
you generalize then and convert into function that you can reuse.
So you can with come effort accumulate collection of functions
performing transformations that you need.

I would be better if FriCAS already had builting functions doing
transformation that you want.  But there is design effort to
identify gnerally useful operations.  Even more complicated issue
it how to make them play nice with rest of FriCAS.  For example,
integrator to work properly needs to simplify things, which
in practice means that as first step interator will "break"
all your boxes and parens and arrange things back in defualt way.

So possible altnative could be different type that "keeps form"
of exprassions and chanes tham only given explicit commands.
There were some "proof of concept" attempts to create such
domain but nothing general and mature enough to include in
FriCAS.

Instead, people use limited approches that cover some case
combined with ad-hoc tricks.

-- 
                              Waldek Hebisch

-- 
You received this message because you are subscribed to the Google Groups 
"FriCAS - computer algebra system" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to fricas-devel+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/fricas-devel/ZLmCw8JD0ZKTR432%40fricas.math.uni.wroc.pl.

Reply via email to