distributive property

6 views
Skip to first unread message

68th

unread,
Jul 18, 2023, 1:03:35 PM7/18/23
to fricas...@googlegroups.com
Hello,

How to make FriCAS distribute over addition?

For example, (a+b)*c into a*c+b*c.

Tried rule to no avail.

(1) -> rule (a+b)*c == a*c+b*c  
  Line   1: rule (a+b)*c == a*c+b*c
           .........A
  Error  A: syntax error at top level
  Error  A: Improper syntax.
   2 error(s) parsing

Ralf Hemmecke

unread,
Jul 18, 2023, 3:04:23 PM7/18/23
to fricas...@googlegroups.com
On 18.07.23 19:03, '68th' via FriCAS - computer algebra system wrote:
> How to make FriCAS distribute over addition?
>
> For example, (a+b)*c into a*c+b*c.

Thank you for this question. I am currently trying to put a collections
of such simple things into a notebook. And I'll probably also take that
example.

So please do not hesitate to ask such seemingly stupid questions. FriCAS
is known to have a steep learning curve. I would like to cure it by
providing many more examples that FriCAS beginners struggle with.

Let me try to "solve" your problem.

Would you call the following behaviour of FriCAS a bit weird?

(204) -> (a+b)*c

(204) (b + a)c
Type: Polynomial(Integer)

(205) -> (c+b)*a

(205) a c + a b
Type: Polynomial(Integer)

No, it is not. And for that to understand you always have to keep in
mind that in contrast to most other computer algebra systems, every
object in FriCAS has a type, above you see Polynomial(Integer).
Type information can be switched on or off via

)type on
)type off

When you type something into a FriCAS session like (a+b)*c, then the
interpreter tries to make sense out of this information. In particular,
it tries to find an appropriate type for your input. In your case,
Polynomial(Integer).

What is Polynomial(Integer). Mathematically, that is the ring Z[X] where
X is the set of any variable (symbol) you can think of, i.e. a ring in
infinitely many variables. All those variable are are sorted and this
sorting agrees with the order in the type Symbol. We have

(207) -> a < b

(207) true

(208) -> b < c

(208) true

So c is the biggest variable. In fact your polynomial lives in
Z[a][b][c]. Yes, it is a polynomial in c with coefficients in Z[a][b].
So (a+b)*c is a polynomial in c (of degree 1 with coefficient (a+b)
being a polynomial (of degree 1) in b with leading coefficient 1 and the
"constant" being the polynomial a from Z[a].

Now how would you print a polynomial in c? Right, as a sum of terms of
the form coefficient*c^n. The coefficient is (a+b) and n is 1 in your
case. So printing (a+b)*c is perfectly fine. That explains (204) from above.

What about (205)? Well, also (c+b)*a is a polynomial of degree 1 in c
having the coefficient a. That explains the a*c part. The "constant"
term of this polynomial is the polynomial a*b (degree 1 in b and
coefficient a).

Good. That explains what FriCAS does, but does not solve your problem.

In fact, I do not know the solution myself. FriCAS certainly knows about
the distributive law, but the answer to your question depends on what
you actually want to achieve. Let me give you one solution. That simply
converts your input into a type that always prints its elements in a
distibuted form.

(209) -> ((a+b)*c)::DistributedMultivariatePolynomial([a,b,c],Integer)

(209) a c + b c
Type: DistributedMultivariatePolynomial([a,b,c],Integer)

However, now the type is something else.

Please pose more questions if something is or becomes unclear.

Ralf

Prof. Dr. Johannes Grabmeier

unread,
Jul 18, 2023, 4:44:29 PM7/18/23
to fricas...@googlegroups.com
To Ralf's very useful remarks to answer your question let me add the
following trick, which seems to be very userful for beginners, too: The
trick is to define (interpreter) variables a, b and c which point to
objects in the desired distributed domain, which are a, b, c. This
forces the interpreter not to choose Polynomal Integer , but direktly
allows to do the desired operation in dmp.

(7) -> dmp := DMP([a,b,c], Integer)

   (7)  DistributedMultivariatePolynomial([a,b,c],Integer)
Type: Type
(8) -> a : dmp := a

   (8)  a
                                            Type:
DistributedMultivariatePolynomial([a,b,c],Integer)
(9) -> b : dmp := b

   (9)  b
                                            Type:
DistributedMultivariatePolynomial([a,b,c],Integer)
(10) -> c : dmp := c

   (10)  c
                                            Type:
DistributedMultivariatePolynomial([a,b,c],Integer)
(11) -> (a+b)*c

   (11)  a c + b c
                                            Type:
DistributedMultivariatePolynomial([a,b,c],Integer)

Am 18.07.23 um 21:04 schrieb Ralf Hemmecke:

Ralf Hemmecke

unread,
Jul 18, 2023, 5:14:40 PM7/18/23
to fricas...@googlegroups.com
> trick is to define (interpreter) variables a, b and c which point to
> objects in the desired distributed domain, which are a, b, c. This
> forces the interpreter not to choose Polynomal Integer , but direktly
> allows to do the desired operation in dmp.

True.

Actually, I am not so sure to suggest this. Recently, I worked quite
some bit in the interpreter and I must say that with a not well planned
session, it is sometimes inconvenient having types declared on some
identifiers.

The reason is that if I can say

(210) -> foo := 1

(210) 1
Type: PositiveInteger
(211) -> foo := "hello"

(211) "hello"
Type: String
(212) -> foo

(212) "hello"
Type: String

But I get

b(213) -> bar: Integer := 1

(213) 1
Type: Integer
(214) -> bar := "hola"

Cannot convert right-hand side of assignment
"hola"

to an object of the type Integer of the left-hand side.

(214) -> bar: String := "hola"

You cannot declare bar to be of type String because either the
declared type of bar or the type of the value of bar is different
from String .

No, I am not saying that this behaviour of FriCAS is bad. Actually, I
rather like it. The point is that I did not know until I figured out
that there is a different behaviour for undeclared and declared identifiers.

However, good that you mentioned it. I will also put this into the
notebook. It's good if beginners learn that right away.

Some addition here.

> (7) -> dmp := DMP([a,b,c], Integer)
>
>    (7)  DistributedMultivariatePolynomial([a,b,c],Integer)
> Type: Type
> (8) -> a : dmp := a

Line (8) seems to look pretty stupid, but, in fact, almost all computer
algebra systems have this. The a on the left of := is actually an
identifier of the SPAD language (like in any other programming
language). On the right of := the a is a value.

(214) -> dmp := DMP([a,b,c], Integer)

(214) DistributedMultivariatePolynomial([a,b,c],Integer)
Type: Type
(215) -> a

(215) a
Type: Variable(a)

Hmmmm, the a on the lefthand side is of type Variable(a). It shouldn't
be possible to assign this to some identifier that has type dmp.

Again, the interpreter jumps in and tries to convert the a of type
Variable(a) into the value a of type
DistributedMultivariatePolynomial([a,b,c],Integer) and then assign it to
the identifier a. So when we now enter a, the interpreter interprets
this as the identifier a and this identifier has a value, namely a
(being of type DistributedMultivariatePolynomial([a,b,c],Integer).

(216) -> a : dmp := a

(216) a
Type: DistributedMultivariatePolynomial([a,b,c],Integer)
(217) -> a

(217) a
Type: DistributedMultivariatePolynomial([a,b,c],Integer)

Ralf

68th

unread,
Jul 19, 2023, 11:17:48 AM7/19/23
to fricas...@googlegroups.com
Thank you Ralf for the explanation. Let's take the cosine formula c²=a²+b²-(2ab)cos(γ). I want to substitute a with (k+l)/2 and b with (l-k)/2 to get c²=(k²+l²+(k²-l²)cos(γ))/2. Then using the distributive property and factoring out k and l I want to get c²=(k²(1+cos(γ))+l²(1-cos(γ)))/2. How can I do this elementary algebra in FriCAS?

------- Original Message -------
> So (a+b)c is a polynomial in c (of degree 1 with coefficient (a+b)
> being a polynomial (of degree 1) in b with leading coefficient 1 and the
> "constant" being the polynomial a from Z[a].
>
> Now how would you print a polynomial in c? Right, as a sum of terms of
> the form coefficientc^n. The coefficient is (a+b) and n is 1 in your
> case. So printing (a+b)c is perfectly fine. That explains (204) from above.
>
> What about (205)? Well, also (c+b)a is a polynomial of degree 1 in c
> having the coefficient a. That explains the ac part. The "constant"
> term of this polynomial is the polynomial ab (degree 1 in b and

68th

unread,
Jul 19, 2023, 11:32:01 AM7/19/23
to fricas...@googlegroups.com
I appreciate your help Professor Grabmeier. I must admit I'm astonished to learn that we need tricks to do elementary algebra in a computer algebra system.

------- Original Message -------

Prof. Dr. Johannes Grabmeier

unread,
Jul 19, 2023, 12:21:17 PM7/19/23
to '68th' via FriCAS - computer algebra system
reading Ralf'ss explanations again should make that clear. Actually,
this really is the strength of FriCAS. The trick is only for convenient
typing in.

Am 19.07.23 um 17:31 schrieb '68th' via FriCAS - computer algebra system:
--
Mit freundlichen Grüßen

Johannes Grabmeier

Prof. Dr. Johannes Grabmeier,
Köckstraße 1, D-94469 Deggendorf
Tel. +49-(0)-991-2979584, Tel. +49-(0)-151-681-70756
Fax: +49-(0)-991-2979592

Ralf Hemmecke

unread,
Jul 19, 2023, 12:27:23 PM7/19/23
to fricas...@googlegroups.com
On 19.07.23 17:31, '68th' via FriCAS - computer algebra system wrote:
> I appreciate your help Professor Grabmeier. I must admit I'm
> astonished to learn that we need tricks to do elementary algebra in a
> computer algebra system.

Well, FriCAS maybe difficult for beginners and it may seem that one has
to use a lot of tricks to do what one wants, but look for example
through this

https://fricas.github.io/fricas-notebooks/FriCAS-SkewPolynomial.html

and try to achieve the same with another CAS. Or (we all know that
taylor series form a ring T, squrae matrices of size 2x2 with entries
being Taylor series also form a ring M. Can you create a structure that
is a polynomial ring with in the variable x whose coefficients live in
M? In FriCAS you can. You have to create all these rings, but it's
possible. Try to do this in Maple or Mathematica. First of all, if I am
not wrong, they do not have infinite Taylor series, only truncated ones.
So you first have to program these.

So it all depends on what you want to use the CAS for. Some systems try
to be generic, FriCAS is better at handling concrete algebraic
structure. You can do fancy things with FriCAS that you might not even
have learned in you mathematica curriculum yet. But for that you have to
invest some time and understand how FriCAS is different from typeless CAS.

Ralf

Ralf Hemmecke

unread,
Jul 19, 2023, 12:46:28 PM7/19/23
to '68th' via FriCAS - computer algebra system
> Let's take the cosine formula c²=a²+b²-(2ab)cos(γ).

Ah, you want to challenge me. ;-) No, honestly, I am grateful that you
pose such questions.

> I want to
> substitute a with (k+l)/2 and b with (l-k)/2 to get
> c²=(k²+l²+(k²-l²)cos(γ))/2. Then using the distributive property and
> factoring out k and l I want to get c²=(k²(1+cos(γ))+l²(1-cos(γ)))/2.
> How can I do this elementary algebra in FriCAS?

(323) -> eq := c^2 = a^2 + b^2 -(2*a*b)*cos(gamma)

2 2 2
(323) c = - 2 a b cos(gamma) + b + a
Type: Equation(Expression(Integer))

(324) -> map(x +-> subst(x,[a=(l+k)/2, b=(l-k)/2]), eq)

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

Is that what you want?

Ralf

68th

unread,
Jul 20, 2023, 9:29:23 AM7/20/23
to fricas...@googlegroups.com
------- Original Message -------
On Wednesday, July 19th, 2023 at 4:46 PM, Ralf Hemmecke <ra...@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)

I don't think that I fully understand this command but at least the result is okay.

> Is that what you want?
>
> Ralf

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(γ))?

Thank you in advance.

Ralf Hemmecke

unread,
Jul 20, 2023, 10:21:58 AM7/20/23
to fricas...@googlegroups.com
On 20.07.23 15:29, '68th' via FriCAS - computer algebra system wrote:

>> (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.

Sure. In FriCAS, can achieve that

a b

(with a space inbetween) means a*b, but I do not explain that to a
beginner. If you write ab, it always denotes an identifier or variable
that consists of the two letters a and b (and is *one* thing. So cos is
one thing, namely, a function. In fact, I understood your notation as
mathematica (and I was probably right). Actually, mathematical notation
is not always unambiguous. But and input for a CAS must be clear,
otherwise if you enter nonsense, you get nonsense back.

>> (324) -> map(x +-> subst(x,[a=(l+k)/2, b=(l-k)/2]), eq)
>
> I don't think that I fully understand this command

(13) -> -- Let's take a look at what the above command does.
(13) -> -- `eq` is an equation that consists of a left- and righthand side.
(13) -> lhs(eq)

2
(13) c
Type: Expression(Integer)
(14) -> rhs eq

2 2
(14) - 2 a b cos(gamma) + b + a
Type: Expression(Integer)
(15) -> -- NB: If a function has only one argument and this argument
(15) -> -- consists just of one part, then you can leave out the
parentheses.
(15) -> -- There is a function `map: (S -> S, %) -> %` in
(15) -> -- [Equation](https://fricas.github.io/api/Equation.html)(S) where
(15) -> -- the $S$ in our case is
(15) -> --
[Expression](https://fricas.github.io/api/Expression)([Integer](https://fricas.github.io/api/Integer)).
(15) -> -- The first argument of `map` is a function from $S$ to $S$ and
this
(15) -> -- is exactly what
(15) -> x +-> subst(x,[a=(l+k)/2,b=(l-k)/2])

l + k l - k
(15) x +-> subst(x,[a = -----, b = -----])
2 2
Type: AnonymousFunction
(16) -> -- is, a mapping from x to what is on the right of `+->` (which
should
(16) -> -- somewhat resemble the mathematical $\mapsto$ notation).
(16) -> --
(16) -> -- The second argument to `map` is the equation `eq` itself.
(16) -> -- According to its specification, `map` applies the function
(16) -> -- to the righthand and the lefthand side of the equation.
(16) -> -- In our case, it will do nothing on the lefthand side,
(16) -> -- but on the righthand side it substitutes $\frac{l+k}{2}$ for $a$,
(16) -> -- and similarly $\frac{l-k}{2}$ for $b$.

Hope that explains it.

> 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(γ))?

Try the following.

(17) -> eq := c^2 = a^2 + b^2 -(2*a*b)*cos(gamma)

2 2 2
(17) c = - 2 a b cos(gamma) + b + a
Type:
Equation(Expression(Integer))
(18) -> ex := subst(rhs eq,[a=(l+k)/2,b=(l-k)/2])

2 2 2 2
(- l + k )cos(gamma) + l + k
(18) -------------------------------
2
Type:
Expression(Integer)
(19) -> ex :: DistributedMultivariatePolynomial([k,l],Expression Integer)

cos(gamma) + 1 2 - cos(gamma) + 1 2
(19) -------------- k + ---------------- l
2 2
Type:
DistributedMultivariatePolynomial([k,l],Expression(Integer))

Note that now the resulting type has a coefficient ring
Expression(Integer) (not just Integer).

Admittedly, that's a bit dangerous, because how can FriCAS decide
that your input k is the variable of
DistributedMultivariatePolynomial([k,l],Expression Integer) and
does not belong to the coefficient domain Expression(Integer)?
It cannot unless the user help. Anyway, here is a big problem.

You can also achieve the following with exposed lokal variable in other
CAS. So be careful.

First, just a macro to make things shorter...

(20) -> Dkl ==> DistributedMultivariatePolynomial([k,l],Expression Integer)

Type: Void

The variable k.

(21) -> k1 := k::Dkl

(21) k
Type:
DistributedMultivariatePolynomial([k,l],Expression(Integer))
(22) -> k2 := k::Expression(Integer) * 1$Dkl

An expression k that lives in the coefficient domain of the polynomial ring.

(22) k
Type:
DistributedMultivariatePolynomial([k,l],Expression(Integer))
(23) -> [degree(k1,k), degree(k2,k)]

(23) [1, 0]
Type:
List(NonNegativeInteger)
(24) -> k1-k2

(24) k - k
Type:
DistributedMultivariatePolynomial([k,l],Expression(Integer))

That is, of course, not 0. And FriCAS is right. The input is what is
dangerous.

Ralf

Waldek Hebisch

unread,
Jul 20, 2023, 12:01:04 PM7/20/23
to '68th' via FriCAS - computer algebra system
On Tue, Jul 18, 2023 at 05:03:23PM +0000, '68th' via FriCAS - computer algebra system wrote:
> Hello,
>
> How to make FriCAS distribute over addition?
>
> For example, (a+b)*c into a*c+b*c.
>
> Tried rule to no avail.

Right question is what do you really want? Each FriCAS type has
its own rules how data is internally represented and how it is
printed. Polynomial(Integer) (which as Ralf wrote) is default
type for you input, used canonical representaion which means
that mathematically equal polynomials have the same representation.
So for "distribute" really make no sense: all transformation
needed to check equality of polyniomial are performed automatically.

If you are interested in "visible" result, that is matter of
printing. Currenly normal printing routines somewhat follow
internal structure of the type. That is somewhat clumsy,
because simplest way of changing printed form is do type
converion to different type with different internal representation.

For purpose of calculation FriCAS approch means that users
automatically get resonably strong simplification. For example
may years ago ocasional FriCAS user (who apperenty asked
before trying) asked me what do to simplify about half text
screen sized expression in FriCAS. The anwser was: input it
in FriCAS and FriCAS will automatically perfrom the simplification.

If you want to do calulation by hand and use FriCAS as a "notebook",
then current FriCAS behaviour may be frustrating, you need special
effort to put results in form that prints as you want. OTOH,
if you are interested in final result of calculations, that
in same case FriCAS defult behaviour will give you simplifications
that you want. There is bunch of "simplifying" routines that do
more than appropriate in default behaviour.

Much of normal work probably will be done in Expression(Integer),
I will write about this in separate mail.

--
Waldek Hebisch

Waldek Hebisch

unread,
Jul 20, 2023, 2:53:58 PM7/20/23
to '68th' via FriCAS - computer algebra system
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 <ra...@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

68th

unread,
Jul 21, 2023, 11:11:29 AM7/21/23
to fricas...@googlegroups.com
------- Original Message -------
On Thursday, July 20th, 2023 at 2:21 PM, Ralf Hemmecke <ra...@hemmecke.org> wrote:

> Try the following.
> (17) -> eq := c^2 = a^2 + b^2 -(2ab)*cos(gamma)
> (18) -> ex := subst(rhs eq,[a=(l+k)/2,b=(l-k)/2])
> (19) -> ex :: DistributedMultivariatePolynomial([k,l],Expression Integer)

Thank you very much.

68th

unread,
Jul 21, 2023, 11:24:28 AM7/21/23
to fricas...@googlegroups.com
------- Original Message -------
On Thursday, July 20th, 2023 at 6:53 PM, Waldek Hebisch <de...@fricas.math.uni.wroc.pl> wrote:

> (34) -> lk := kernels(re)
> (36) -> ker_l := lk(2)
> (37) -> univariate(re, ker_l)
> (38) -> nu := numer(%)
> (40) -> box(l^2*coefficient(nu, 2)) + box(coefficient(nu, 0))

> 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.

Thank you for the information. Maybe I'll get back to this method if I won't be able to do everything I want with commands that Ralf suggests.
Reply all
Reply to author
Forward
0 new messages