Use FriCAS as library from C?

42 views
Skip to first unread message

Tobias

unread,
Dec 12, 2020, 3:53:58 PM12/12/20
to FriCAS - computer algebra system
Hello!

I am interested in using a FriCAS (DoubleFloat -> DoubleFloat) function from C.
Is such a thing easily (out of the box) possible, or has anyone explored that before? Presumably it could be done, at least in principle, see http://www.sbcl.org/manual/index.html#Calling-Lisp-From-C but it's likely difficult and hacky.

While I could launch a new FriCAS and parse the output for each call, this would be too inefficient for my application. An alternative would be to run FriCAS once and stream
input and output for many function calls (as probably SageMath and others do it). Ideally I want to have as little overhead as possible.

I would be happy for any suggestions in that regard!

Thanks,
Tobias

Dima Pasechnik

unread,
Dec 12, 2020, 5:29:33 PM12/12/20
to fricas...@googlegroups.com


On Sat, 12 Dec 2020, 20:53 Tobias, <tobias....@gmail.com> wrote:
Hello!

I am interested in using a FriCAS (DoubleFloat -> DoubleFloat) function from C.
Is such a thing easily (out of the box) possible, or has anyone explored that before? Presumably it could be done, at least in principle, see http://www.sbcl.org/manual/index.html#Calling-Lisp-From-C but it's likely difficult and hacky.

you can call ECL from C (ECL might provide a slightly slower Fricas, but OK).

If I am not mistaken, in SageMath we call Fricas from Python this way (via a Python extension module that embeds ECL as a library).
We certainly do this with Maxima.
Anyway, it certainly is very doable with ECL.



While I could launch a new FriCAS and parse the output for each call, this would be too inefficient for my application. An alternative would be to run FriCAS once and stream
input and output for many function calls (as probably SageMath and others do it). Ideally I want to have as little overhead as possible.

I would be happy for any suggestions in that regard!



Thanks,
Tobias

--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fricas-devel/e1d7929c-b691-4c37-a61c-86a166ef3d10n%40googlegroups.com.

Ralf Hemmecke

unread,
Dec 12, 2020, 5:58:13 PM12/12/20
to fricas...@googlegroups.com
What exact function do you want to call?
Maybe you are satisfied with what the aldor library provides.

https://github.com/pippijn/aldor

Ralf

Waldek Hebisch

unread,
Dec 12, 2020, 6:09:43 PM12/12/20
to fricas...@googlegroups.com
On Sat, Dec 12, 2020 at 11:58:35AM -0800, Tobias wrote:
> Hello!
>
> I am interested in using a FriCAS (DoubleFloat -> DoubleFloat) function
> from C.
> Is such a thing easily (out of the box) possible, or has anyone explored
> that before? Presumably it could be done, at least in principle, see
> http://www.sbcl.org/manual/index.html#Calling-Lisp-From-C but it's likely
> difficult and hacky.

There are no ready example. As Dima mentioned, probably easiest
way is to use ECL to compile FriCAS. ECL has good support for
calling Lisp from C. Then you need to bridge differences
between Lisp and FriCAS: not all Lisp data makes sense for
FriCAS and most FriCAS data is only indirectly exposed to
Lisp. For calling FriCAS from Lisp there is an example,
look at file 'contrib/load-fricas.lisp' in FriCAS sources.

In principle sbcl supports calling Lisp from C, but I am
not sure how easy/conenient it is.

> While I could launch a new FriCAS and parse the output for each call, this
> would be too inefficient for my application. An alternative would be to run
> FriCAS once and stream
> input and output for many function calls (as probably SageMath and others
> do it). Ideally I want to have as little overhead as possible.
>
> I would be happy for any suggestions in that regard!

I would suggest starting from connection via pipe. Any call
between C and FriCAS must convert data. Converting say C
format to communication format, sending this via pipe and
then converting to FriCAS format is less efficient than
more direct convertion but is easier to implement and
may be fast enough. I wrote above "communication format"
because easy way uses text, but one could also use
binary format.


--
Waldek Hebisch

Grégory Vanuxem

unread,
Dec 20, 2020, 3:49:38 PM12/20/20
to fricas...@googlegroups.com
Hi,

Why not do the inverse?
> --
> 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...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/fricas-devel/e1d7929c-b691-4c37-a61c-86a166ef3d10n%40googlegroups.com.



--
__
G. Vanuxem

Tobias Neumann

unread,
Jan 13, 2021, 7:28:48 PM1/13/21
to FriCAS - computer algebra system
Thanks for the many helpful suggestions. Pure Aldor might be an interesting avenue. For prototyping
I will probably first use the interactive mode or SPAD, and then think about pure Aldor vs. an ECL or pipe route.
In that regard I have a few additional questions:

- When using Aldor programs within FriCAS, do I get access to all domains and categories within FriCAS,
or is it a limited subset? Is it documented which ones are available? Concretely I am interested in Puiseux series.
Looking at the source, the Aldor algebra library does seem to have at least a Taylor series. To make it clear:
as a first step I would be interested in writing Aldor programs (instead of SPAD) and load them in FriCAS (with ")compile"), so
not standalone Aldor programs.

- Is UnivariatePuiseuxSeries(Expression(Float), 'x, 0.1::Float) something that is not well-defined, or is it just not implemented?
-> series((0.1::Float)*x,x,0.0::Float)
...
   Cannot find a definition or applicable library operation named
      series with argument type(s)
                              Polynomial(Float)
                                 Variable(x)
                                    Float

Thank you,
Tobias

Ralf Hemmecke

unread,
Jan 13, 2021, 8:12:41 PM1/13/21
to fricas...@googlegroups.com
Hello Tobias,

> Pure Aldor might be an interesting avenue.

Yes, but it comes at a price.

> For prototyping I will probably first use the interactive mode or
> SPAD and then think about pure Aldor vs. an ECL or pipe route.

Well, it depends on what you want to do. If you want to use the
algorithms implemented in FriCAS, then the Aldor way is gone.

Aldor is, in fact, a separate project. It is a compiler and a library
(actually several libraries). The libraries are not compatible with the
FriCAS library.

What the Aldor-FriCAS interface does, is that it allows to use the aldor
COMPILER instead of the FriCAS compiler. Then you have to use Aldor
Syntax instead of SPAD syntax (there are a number of differences,
though). In effect, however, when you use the Aldor compiler in this
way, you generate lisp code for use in FriCAS, i.e. not a standalone
library.

In other words, if you want to use the algorithms from FriCAS in your
program, then the Aldor route will not work.

> Concretely I am interested in
> Puiseux series. Looking at the source, the Aldor algebra library does
> seem to have at least a Taylor series. To make it clear: as a first
> step I would be interested in writing Aldor programs (instead of
> SPAD) and load them in FriCAS (with ")compile"), so not standalone
> Aldor programs.

See above. If you want a standalone library, then either
forget about FriCAS and use what you can find in the Aldor (algebra)
library or you must connect your program to FriCAS in some way and then
you can use everything from FriCAS.

There is not Puiseux series implementation in the aldor library, but if
you look at how it is done in FriCAS, then it is clear that an
implementation is pretty easy.

- Is UnivariatePuiseuxSeries(Expression(Float), 'x, 0.1::Float)
> something that is not well-defined, or is it just not implemented? ->
> series((0.1::Float)*x,x,0.0::Float) ... Cannot find a definition or
> applicable library operation named series with argument type(s)
> Polynomial(Float) Variable(x) Float
Maybe this gives yo an idea.

(1) -> F ==> Float
(2) -> E ==> Expression F
(3) -> P ==> UnivariatePuiseuxSeries(E, 'x, 0.1::F::E)
(4) -> z := monomial(1,1)$P

(4) (x - 0.1)
Type: UnivariatePuiseuxSeries(Expression(Float),x,0.1)
(5) -> z^3

3
(5) (x - 0.1)
Type:
UnivariatePuiseuxSeries(Expression(Float),x,0.1)
(9) -> 1/(1-z)

(9)
2 3 4 5
1.0 + (x - 0.1) + (x - 0.1) + (x - 0.1) + (x - 0.1) + (x - 0.1)
+
6 7 8 9 10
(x - 0.1) + (x - 0.1) + (x - 0.1) + (x - 0.1) + (x - 0.1)
+
11
O((x - 0.1) )

Ralf

Tobias Neumann

unread,
Jan 17, 2021, 11:57:42 PM1/17/21
to fricas...@googlegroups.com
Thanks for that insight. I certainly like the Aldor language. I had always wished
for a computer algebra package in Haskell, and Aldor seem to be just like that. 

I think my confusion came from the "#include "fricas"", that you use when writing Aldor programs
for use with Fricas, and that you can use some basic types like Integer (AldorInteger) interchangeably with the Fricas types.
It was not clear to me if Fricas provided wrappers for most (all) of its functions for use within Aldor.
So my current understanding is that there is some correspondence of the most basic types, that allows one
to run the Lisp code generated by Aldor within Fricas. 

With respect to the series expansions, what I would like to understand is: Why does a simple series(0.1*x, x=0.0) not work,
even with type annotations? This becomes relevant when I start with an expression
Expression(Float) (maybe returned by some function) and want to series expand it. Maybe what you have written
actually leads to an answer to that question, but it's not clear to me.

Tobias

--
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...@googlegroups.com.

Ralf Hemmecke

unread,
Jan 18, 2021, 2:15:26 AM1/18/21
to fricas...@googlegroups.com
> With respect to the series expansions, what I would like to understand is:
> Why does a simple series(0.1*x, x=0.0) not work,
> even with type annotations?

>> (1) -> F ==> Float
>> (2) -> E ==> Expression F
>> (3) -> P ==> UnivariatePuiseuxSeries(E, 'x, 0.1::F::E)
>> (4) -> z := monomial(1,1)$P

The two most important lines here are (3) and (4).

Since (3) actually does nothing than tell the system that P abbreviates
Puiseux series, let's concentrate on (4). That line says "let z be the
variable of P regarded as a Puiseux series over E (with a variable name
x and expanded abount 0.1).

Now let us suppose you do not do the above and let me give YOU the
expression

series(x, x=0)

how do you know in what domain I want my series to live? Is it with
coefficients over the integers?

But that only can give you a hint that not only FriCAS would have a
problem in figuring out my intend.

Now look at this (see end of mail for full detail).

(1) -> )set message bottom on
(1) -> series(0.1*x, x=0)

You can ask FriCAS via ")set message bottom on" to show you what it will
try to make sense out of your expression. FriCAS must interpret every
single letter of it and try to find a function "series" with appropriate
types. Since x is not assigned, the best it can do is to consider it as
something of type Variable(x). Of course that doesn't work for 0.1*x, so
FriCAS tries to find an appropriate type for *: (Float, X) -> Y where X
and Y are unknown types and Variable(x) must be convertible to X.
"convertible to" simply means that FriCAS must find (among the currently
exposed library functions) a function with name "coerce", "convert" or
"retract" that has the appropriate type. Here it seemingly finds one,
namely converting Variable(x) to Polynomial(Float). So, we can use
*: (Float, Polynomial(Float)) -> Polynomial(Float).
Same thing for "x=0", where it first figures out that the type for "="
could be "(Polynomial(Integer), Polynomial(Integer) ->
Equation(Polynomial(Integer)) might work.
Bad luck now for the "series" function, since there is no such function
with the respective types.
Obviously, FriCAS gives up after looking at the available types for
"series".

So the only real hint I can give is that you have to help FriCAS in
figuring out what you actually want. FriCAS is unable (as anyone) would
to figure out what your intentions are. There are simply too many
coefficient domains that might work.

Maybe you give one of the expressions that you are working on so that I
might try to help you expand this into a Puiseux series.

Ralf

====================================================================

(1) -> )set message bottom on
(1) -> series(0.1*x, x=0)

Function Selection for float
Arguments: (INT, INT, PI)
Target type: FLOAT
From: FLOAT

[1] signature: (INT, INT, PI) -> FLOAT
implemented: slot $(Integer)(Integer)(PositiveInteger) from FLOAT


Function Selection for *
Arguments: (FLOAT, VARIABLE(x))

[1] signature: (FLOAT, POLY(FLOAT)) -> POLY(FLOAT)
implemented: slot $(Float)$ from POLY(FLOAT)
[2] signature: (POLY(FLOAT), POLY(FLOAT)) -> POLY(FLOAT)
implemented: slot $$$ from POLY(FLOAT)


Function Selection for equation
Arguments: (VARIABLE(x), NNI)

[1] signature: (POLY(INT), POLY(INT)) -> EQ(POLY(INT))
implemented: slot $(Polynomial (Integer))(Polynomial (Integer))
from EQ(POLY(INT))


Function Selection for series
Arguments: (POLY(FLOAT), EQ(POLY(INT)))
-> no function series found for arguments (POLY(FLOAT), EQ(POLY(INT)))

Function Selection for map by coercion facility (map)
Arguments: ((POLY(INT) -> INT), EQ(POLY(INT)))
Target type: EQ(INT)

[1] signature: ((POLY(INT) -> INT), EQ(POLY(INT))) -> EQ(INT)
implemented: slot (Equation (Integer))(Mapping (Integer)
(Polynomial (Integer)))(Equation (Polynomial (Integer))) from
EQ2(POLY(INT),INT)


Function Selection for series
Arguments: (UP(x,FLOAT), EQ(POLY(INT)))
-> no function series found for arguments (UP(x,FLOAT), EQ(POLY(INT)))

Function Selection for map by coercion facility (map)
Arguments: ((POLY(INT) -> INT), EQ(POLY(INT)))
Target type: EQ(INT)

[1] signature: ((POLY(INT) -> INT), EQ(POLY(INT))) -> EQ(INT)
implemented: slot (Equation (Integer))(Mapping (Integer)
(Polynomial (Integer)))(Equation (Polynomial (Integer))) from
EQ2(POLY(INT),INT)

There are 4 exposed and 1 unexposed library operations named series
having 2 argument(s) but none was determined to be applicable.
Use HyperDoc Browse, or issue
)display op series
to learn more about the available operations. Perhaps
package-calling the operation or using coercions on the arguments
will allow you to apply the operation.

Cannot find a definition or applicable library operation named
series with argument type(s)
Polynomial(Float)
Equation(Polynomial(Integer))

Perhaps you should use "@" to indicate the required return type,
or "$" to specify which version of the function you need.

Tobias Neumann

unread,
Jan 18, 2021, 1:35:50 PM1/18/21
to fricas...@googlegroups.com
Thanks for the detailed answer. I realize that FriCAS is not able to find a matching signature of series
or coerce the arguments into something that works. But it appears strange
to me, since this is the case even with type annotations for all arguments. 

I found that just coercing my full expression into a Puiseux series works. For example:
 > log(sqrt(t+1.0))*sqrt(t) + 1/t :: UnivariatePuiseuxSeries(Expression(Float),t,0.0)
gives the answer.

What puzzles me is that in the same way I would have expected that 
> series(log(sqrt(t+1.0))*sqrt(t) + 1/t, t=0.0) :: UnivariatePuiseuxSeries(Expression(Float),t,0.0)
should work.

When I look at
I see that series (or puiseux) has a signature "puiseux: (FE, Equation FE) -> Any",
where FE can be FunctionSpace R and R is Comparable. Furthermore it is
> Expression(Float) has FunctionSpace(Float)
true

so 
> puiseux((0.1*x) :: Expression(Float), (x=0.0) :: Equation(Expression(Float)))
should have the right type signature, but ")set message bottom on" tells me:
 Function Selection for puiseux
      Arguments: (EXPR(FLOAT), EQ(EXPR(FLOAT)))
   -> no function puiseux found for arguments (EXPR(FLOAT), EQ(EXPR(FLOAT)))

In any case the "workaround" works fine for me now and I can try to understand this
issue once I'm more familiar with FriCAS.

Tobias 

Waldek Hebisch

unread,
Jan 20, 2021, 2:28:00 PM1/20/21
to fricas...@googlegroups.com
On Mon, Jan 18, 2021 at 01:35:38PM -0500, Tobias Neumann wrote:
> Thanks for the detailed answer. I realize that FriCAS is not able to find a
> matching signature of series
> or coerce the arguments into something that works. But it appears strange
> to me, since this is the case even with type annotations for all arguments.

Main reason is that you request rather bizzare operation. Namely,
main FriCAS 'series' routine does not work for floating point
numers. This is encoded in type constraints:

(11) -> ExpressionToUnivariatePowerSeries(Float, Expression(Float))

ExpressionToUnivariatePowerSeries(Float,Expression(Float)) is not a
valid type.

(12) Se := ExpressionToUnivariatePowerSeries(Integer, Expression(Integer))
(13) -> series(log(sqrt(t+1))*sqrt(t) + 1/t, t = 0)$Se

3 5 7 9
- - - -
- 1 1 2 1 2 1 2 2
(13) t + - t - - t + - t + O(t )
2 4 6
Type: UnivariatePuiseuxSeries(Expression(Integer),t,0)

So to work with floating point numbers you need workarounds,
and interpreter will not introduce them automatically
(because they may fail in more general situations).

> I found that just coercing my full expression into a Puiseux series works.
> For example:
> > log(sqrt(t+1.0))*sqrt(t) + 1/t ::
> UnivariatePuiseuxSeries(Expression(Float),t,0.0)
> gives the answer.

Above most computations are done at level of series (which is
a workaround for your problem). This does not solve general
problem of converting 'Expression(Float)' to series:
in general for convertion one need to simplify first
and then "replay" operations in series deomain. Simplification
part does not work when there are floating point coefficients.
Of course, as long as expression is already simplified
the above works OK.

> What puzzles me is that in the same way I would have expected that
> > series(log(sqrt(t+1.0))*sqrt(t) + 1/t, t=0.0)
> :: UnivariatePuiseuxSeries(Expression(Float),t,0.0)
> should work.

As I wrote 'series' does not work with floating point numbers.

> When I look at
> https://fricas.github.io/api/ExpressionToUnivariatePowerSeries.html
> I see that series (or puiseux) has a signature "puiseux: (FE, Equation FE)
> -> Any",
> where FE can be FunctionSpace R and R is Comparable. Furthermore it is
> > Expression(Float) has FunctionSpace(Float)
> true

'series' needs ability to compute basis over rational numbers
of space spanned by finite number of elements of R. When
R is Float this is clearly not satisfied: at representaion
level all Float-s are rational numbers so only possiblity
would be to consider Float as one dimensional space over
ratonals, that is treat it as identical to rational numbers.
But due to approximate nature of floating point numbers
basic equalites for vector space fail.

Note that some other systems will quietly convert floating
point numbers to rationals. But FriCAS takes types
seriously and allows only explicit convertion -- if you
want convertion to rationals you need to add it explicitly.

--
Waldek Hebisch
Reply all
Reply to author
Forward
0 new messages