Problem with function definition

18 views
Skip to first unread message

Ralf Hemmecke

unread,
Mar 25, 2024, 10:41:56 AMMar 25
to fricas-devel
Hello,

does somebody see my error? I don't understand why the function "nicer"
does not work, but the individual commands on the input do.
What I also find strange is that the error message for "nicer" changes
in the end.

The commands of the following session are attached.

Thanks in advance.
Ralf


%%% (1) -> ZZ ==> Integer

Type: Void
%%% (2) -> EX ==> Expression

Type: Void
%%% (3) -> combineRadicals := rule sqrt(x)*sqrt(y) == sqrt(x*y)

+-+ +-+ +---+
(3) %B\|x \|y == %B\|x y
Type:
RewriteRule(Integer,Integer,Expression(Integer))
%%% (4) -> nicer(x: EX ZZ): AlgebraicNumber == ( AM ==>
AlgebraicManipulations(ZZ, EX ZZ); xx :=
combineRadicals(rootSplit(x)$AM); rs := rsimp((numer
xx)::EX(ZZ))$RootSimplification; zz := rootSplit(rs)$AM / denom xx;
combineRadicals(zz) :: AlgebraicNumber)
Function declaration nicer : Expression(Integer) -> AlgebraicNumber
has been added to workspace.

Type: Void
%%% (5) -> nicer x0

>> System error:
The variable $$$ is unbound.

%%% (5) -> x0 :=
sqrt((184726398605281*sqrt(-163)+14962838287027761)/20010)/17502080

+--------------------------------------------+
| +-----+
|184726398605281 \|- 163 + 14962838287027761
|--------------------------------------------
\| 20010
(5) -----------------------------------------------
17502080
Type:
AlgebraicNumber
%%% (6) -> AM ==> AlgebraicManipulations(ZZ, EX ZZ)

Type: Void
%%% (7) -> xx := combineRadicals(rootSplit(x0)$AM)

+--------------------------------------------+
| +-----+
\|184726398605281 \|- 163 + 14962838287027761
(7) -----------------------------------------------
+-----+
17502080 \|20010
Type:
Expression(Integer)
%%% (8) -> rs := rsimp((numer xx)::EX(ZZ))$RootSimplification;

Type:
Union(Expression(Integer),...)
%%% (9) -> zz := rootSplit(rs)$AM / denom xx;

Type:
Expression(Integer)
%%% (10) -> combineRadicals(zz) :: AlgebraicNumber

+-----+ +-------+
(13591409 \|- 163 + 2215399667)\|1630815
(10) ------------------------------------------
57085309190400
Type:
AlgebraicNumber
%%% (11) -> nicer x0

>> System error:
The function BOOT::|*1;nicer;1;initial| is undefined.
foo.input

Waldek Hebisch

unread,
Mar 25, 2024, 11:13:42 AMMar 25
to fricas...@googlegroups.com
On Mon, Mar 25, 2024 at 03:41:51PM +0100, Ralf Hemmecke wrote:
> Hello,
>
> does somebody see my error? I don't understand why the function "nicer" does
> not work, but the individual commands on the input do.

This is a bug in FriCAS. RootSimplification uses interpreter to
initialize its variables. However, this does not work when first
use of RootSimplification is inside a function. It is not clear
whom to blame, RootSimplification uses interpreter differently than
rest of algebra.

As a workaround one can do something like

rsimp(1)$RootSimplification

to initialize RootSimplification. Then I see different error:

nicer x0

Compiling function nicer with type Expression(Integer) ->
AlgebraicNumber
Conversion failed in the compiled user function nicer .

Cannot convert the value from type Union(Expression(Integer),
"failed") to Expression(Integer) .

> What I also find strange is that the error message for "nicer" changes in
> the end.

This is expected when errors are releated to initialization, failed
initialization may leave traces and second attempt works differently.

BTW: There is another trouble with interpreter and RootSimplification:
initializing RootSimplification also assigns values to a few variables
in user session. ATM it is not clear to me what to do: doing initialization
as Spad code triggers very bad behaviour in Spad compiler (very long compile
time) and after that in sbcl (running out of memory).

--
Waldek Hebisch

Ralf Hemmecke

unread,
Mar 25, 2024, 2:00:48 PMMar 25
to fricas...@googlegroups.com
On 3/25/24 16:13, Waldek Hebisch wrote:
> This is a bug in FriCAS. RootSimplification uses interpreter to
> initialize its variables. However, this does not work when first
> use of RootSimplification is inside a function.

Ah. OK. Thank you.

What about documenting this?

> It is not clear whom to blame, RootSimplification uses interpreter
> differently than rest of algebra.

Oh. I actually do not understand at all, why you implemented
RootSimplification via calling "interpret". Is that really necessary?
You mentioned that the compiler behaves badly with the respective SPAD
initialization. But what exactly does that mean?
The expression in rp3s looks big, but why would that be unmanageable by
by the compiler?

Probably you also do not like that the interpreter is called in SPAD
code. That looks strange to me, more like a workaround. AFAIU, it is a
workaround.

> As a workaround one can do something like
>
> rsimp(1)$RootSimplification
>
> to initialize RootSimplification.

Thank you.

> BTW: There is another trouble with interpreter and
> RootSimplification: initializing RootSimplification also assigns
> values to a few variables in user session.

That is a *big* trouble if you use variables that are likely to be used
in user code before the initialization happens in RootSimplification.
The simplest workaround for this is probably to use variables starting
with underscore, i.e. _a, etc. or generate a new symbol and concatenate
with "_a", "_b", etc. and replace the variables in the string
expressions of rp... by the respective symbol before it it given to
interpret. str_to_expr could be a good place to do that string
modification. Also "eI" is a bad name for hidden initialization.

%%% (1) -> a: Integer := 1

(1) 1
Type:
Integer
%%% (2) -> rsimp(1)$RootSimplification

Cannot convert right-hand side of assignment
a

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

> ATM it is not clear to me what to do: doing initialization as Spad
> code triggers very bad behaviour in Spad compiler (very long compile
> time) and after that in sbcl (running out of memory).

Do you know the real cause of why the compiler behaves so badly?

Ralf

Waldek Hebisch

unread,
Mar 25, 2024, 5:54:19 PMMar 25
to fricas...@googlegroups.com
On Mon, Mar 25, 2024 at 07:00:44PM +0100, Ralf Hemmecke wrote:
> On 3/25/24 16:13, Waldek Hebisch wrote:
> > This is a bug in FriCAS. RootSimplification uses interpreter to
> > initialize its variables. However, this does not work when first
> > use of RootSimplification is inside a function.
>
> Ah. OK. Thank you.
>
> What about documenting this?

Well, normal thing to do is to fix a bug. Documenting a bug is
least resort, when fix is too hard.

> > It is not clear whom to blame, RootSimplification uses interpreter
> > differently than rest of algebra.
>
> Oh. I actually do not understand at all, why you implemented
> RootSimplification via calling "interpret". Is that really necessary?
> You mentioned that the compiler behaves badly with the respective SPAD
> initialization. But what exactly does that mean?
> The expression in rp3s looks big, but why would that be unmanageable by
> by the compiler?
>
> Probably you also do not like that the interpreter is called in SPAD
> code. That looks strange to me, more like a workaround. AFAIU, it is a
> workaround.

Yes, using interpreter is a workaround. There are actually two releated
problems. One is long compile time in Spad compiler. That should be
eventually fixed by rewiting Spad compiler to use deffierent approach.
More precisely, currently Spad compiler uses recursive approach to
compiling expressions. However, overloading means that given expression
may be analysed multiple times (one for each applicable type).
With recursive approach parts of expression are analysed multiple
times, leading to runtime which is exponential is size of expression.

Alternative is a bottom up approach, where compiler produces all
possible alternatives for each subexpression. On simple expressions
this may be more work than recusive approach (which may finish before
exploring all alternatives), but on more complex expression bottom up
approach avoid reding the same work again and again. Interpreter
uses a variation of bottom up approach, and for expressions in case
is much faster than Spad compiler. Interpreter commits early to one
alternative so may reject some code that Spad compiler accepts.
Also, interpreter has its own quirks that may cause very long
typechecking time. But in this case interpreter works in resonable
time and IMO Spad compiler in the future should use bottom up
approach.

The second problem is sbcl compilation. Apparently when sbcl
sees largish piece of code containing no jump it takes it as
excelent opportunity to optimize. It tries to collect a lot
of information about the code and runs out of memory. Using
interpreter we avoid Lisp compiler. Note that expression I use
are toplevel expressions which are subject to pure interpretation.
Using interpreter function would probably solve problem of Spad
compile time, but we still would have problem with sbcl
compiler.

BTW: I did not try largest expression, but on a smaller expression
sbcl runs out of memory, but ECL works. Still, resulting C
compile time is large (and memory use is large), so those expression
apparently stretch all optimizers. gcc probably got more
tuning on "bad" examples so it handles it (with degraded performance),
but sbcl simply blows up.

> > BTW: There is another trouble with interpreter and RootSimplification:
> > initializing RootSimplification also assigns values to a few variables
> > in user session.
>
> That is a *big* trouble if you use variables that are likely to be used
> in user code before the initialization happens in RootSimplification.
> The simplest workaround for this is probably to use variables starting
> with underscore, i.e. _a, etc. or generate a new symbol and concatenate
> with "_a", "_b", etc. and replace the variables in the string
> expressions of rp... by the respective symbol before it it given to
> interpret. str_to_expr could be a good place to do that string
> modification. Also "eI" is a bad name for hidden initialization.

Well, I hope for better solution. When I wrote the code I (wrongly)
assumend that all variables will be local to the evaluation and will
not affect what user sees. Apparently, currently the only way to
get local variables in interpreter is to use a function. But this
is exactly what I want to avoid, because of sbcl compile time for
a function.

> %%% (1) -> a: Integer := 1
>
> (1) 1
> Type:
> Integer
> %%% (2) -> rsimp(1)$RootSimplification
>
> Cannot convert right-hand side of assignment
> a
>
> to an object of the type Integer of the left-hand side.

Yes.

--
Waldek Hebisch

Waldek Hebisch

unread,
Mar 26, 2024, 12:24:41 AMMar 26
to fricas...@googlegroups.com
On Mon, Mar 25, 2024 at 03:41:51PM +0100, Ralf Hemmecke wrote:
> Hello,
>
> does somebody see my error? I don't understand why the function "nicer" does
> not work, but the individual commands on the input do.
> What I also find strange is that the error message for "nicer" changes in
> the end.

As I wrote, this is a bug in FriCAS. The attached patch seem to
fix the problem

--
Waldek Hebisch
sum6a1.diff

Waldek Hebisch

unread,
Apr 16, 2024, 9:57:34 PMApr 16
to fricas...@googlegroups.com
On Mon, Mar 25, 2024 at 07:00:44PM +0100, Ralf Hemmecke wrote:
>
> %%% (1) -> a: Integer := 1
>
> (1) 1
> Type:
> Integer
> %%% (2) -> rsimp(1)$RootSimplification
>
> Cannot convert right-hand side of assignment
> a
>
> to an object of the type Integer of the left-hand side.

This should be fixed by recent commit which evaluates expression
in fresh environment, so that evaluation from Spad is not affected
by user variables and variables used in evaluation do not leak
to user environment.

--
Waldek Hebisch

Ralf Hemmecke

unread,
Apr 17, 2024, 3:06:23 AMApr 17
to fricas...@googlegroups.com
This sounds great!

Thank you!

Ralf
Reply all
Reply to author
Forward
0 new messages