embedding sage in c or c++

1,038 views
Skip to first unread message

Michael Rubinstein

unread,
Sep 13, 2011, 9:10:45 AM9/13/11
to sage-devel
I'd like to call some sage commands from within a c++ program and use
the
output. My plan is to call very simple 1-4 line sequences of sage
commands, in
order to make use of some of the number theoretic functions built into
sage
(for example, dealing with elliptic curves, number fields, modular
forms).

I found a simple way to do so using popen, but this necessitates
reading the
sage output as strings and then parsing. If the sage output cuts
across many lines,
then the parsing becomes a bit more tricky. I also tried the
instructions at:

http://docs.python.org/extending/embedding.html

but had trouble when I tried to PyRun_SimpleString
a simple sage command (see example 2 below).

Example 1
----------------

Here is a simple proof of concept example.cc program which uses
popen,
(compile with g++ example.cc and run with ./a.out), to factor 2310 by
calling sage.
The result is stored as a string, but it would not be difficult to
parse it further to get
the actual factors as numbers if desired.

#include <stdio.h>
#include <iostream>
#include <string>


using namespace std;

int main (int argc, char *argv[])
{



FILE* sage_output;
sage_output=popen("echo \"factor(2310)\" | sage", "r");

string factorization; // string for storing the result from sage


int MAX_LEN=10000; //maximum length of lines in file
char str_buf[MAX_LEN + 1]; // One extra byte needed
// for the null character

int line_count=0;
while(fgets(str_buf, MAX_LEN + 1, sage_output) != NULL){


line_count++;

//The first four lines look like:
//----------------------------------------------------------------------
//| Sage Version 4.5.3, Release Date:
2010-09-04 |
//| Type notebook() for the GUI, and license() for
information. |
//----------------------------------------------------------------------

if (line_count==5){ // the 5th line of the sage session has
the output that we want

factorization=str_buf;

factorization=factorization.substr(6,strlen(str_buf)-7);
// the 6 removes the `sage: ' from the output, i.e. starts
after the 6th character
// strlen(str_buf)-7 is the length of the output, i.e.
without `sage: ' and without newline
}

}
pclose(sage_output);

cout << "sage returned:" << factorization << endl;



return 0;

}


//============================= END OF EXAMPLE 1
==================================


Example 2
----------------

Next thing I tried to do was to embed sage in a c program, by
following
http://docs.python.org/extending/embedding.html
but that gave me errors at runtime.

For example, the following embed.c progam produced the output/errors
at the bottom
of this post. Any ideas what's wrong? Any ideas of better ways to call
sage from within
c or c++?

/*
sage -sh
gcc -I$SAGE_LOCAL/include/python2.6 $SAGE_LOCAL/lib/python/config/
libpython2.6.a embed.c -o embed; ./embed

See http://docs.python.org/extending/embedding.html
*/


#include <Python.h>

int main(int argc, char *argv[])
{

Py_Initialize();

printf("1+1:\n");
PyRun_SimpleString("print 1+1");

printf("Load sage \n");
PyRun_SimpleString("from sage.all import *");

printf("Factor 2310:\n");
PyRun_SimpleString("print factor(2310)");

Py_Finalize();

return 0;
}


//================================ END EXAMPLE 2 =====================

What happens when I run example 2:

mrubinst$ ./embed
1+1:
2
Loading the Sage library...
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/Applications/sage/local/lib/python2.6/site-packages/sage/
all.py", line 64, in <module>
from sage.misc.all import * # takes a while
File "/Applications/sage/local/lib/python2.6/site-packages/sage/misc/
all.py", line 16, in <module>
from sage_timeit_class import timeit
File "sage_timeit_class.pyx", line 3, in init
sage.misc.sage_timeit_class (sage/misc/sage_timeit_class.c:862)
File "/Applications/sage/local/lib/python2.6/site-packages/sage/misc/
sage_timeit.py", line 12, in <module>
import timeit as timeit_, time, math, preparser, interpreter
File "/Applications/sage/local/lib/python2.6/site-packages/sage/misc/
interpreter.py", line 95, in <module>
import IPython.ipapi
File "/Applications/sage/local/lib/python2.6/site-packages/IPython/
__init__.py", line 58, in <module>
__import__(name,glob,loc,[])
File "/Applications/sage/local/lib/python2.6/site-packages/IPython/
Shell.py", line 42, in <module>
from IPython import ultraTB, ipapi
File "/Applications/sage/local/lib/python2.6/site-packages/IPython/
ultraTB.py", line 99, in <module>
from IPython import Debugger, PyColorize
File "/Applications/sage/local/lib/python2.6/site-packages/IPython/
Debugger.py", line 48, in <module>
if '-pydb' in sys.argv:
AttributeError: 'module' object has no attribute 'argv'
Factoring an integer:
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'factor' is not defined

But typing the python/sage commands into python directly works ok:

mrubinst$ python
Python 2.6.4 (r264:75706, Sep 9 2010, 12:46:47)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from sage.all import *
>>> factor(2310)
2 * 3 * 5 * 7 * 11

Willem Jan Palenstijn

unread,
Sep 13, 2011, 9:32:02 AM9/13/11
to sage-...@googlegroups.com
On Tue, Sep 13, 2011 at 06:10:45AM -0700, Michael Rubinstein wrote:
> Example 2
> ----------------
>
> Next thing I tried to do was to embed sage in a c program, by
> following
> http://docs.python.org/extending/embedding.html
> but that gave me errors at runtime.
>
> For example, the following embed.c progam produced the output/errors at the
> bottom of this post. Any ideas what's wrong? Any ideas of better ways to call
> sage from within c or c++?

Some quick googling suggests you may have to call PySys_SetArgv[Ex] (
http://docs.python.org/c-api/init.html#PySys_SetArgvEx ) to set up sys.argv
after calling Py_Initialize(). I haven't actually tried it, though.


-Willem Jan

Michael Rubinstein

unread,
Sep 13, 2011, 11:46:05 AM9/13/11
to sage-devel

I tried adding PySys_SetArgv(argc, argv); after Py_Initialize();
It gets me further but then gives a strange error message:

Loading the Sage library...


------------------------------------------------------------
Unhandled SIGSEGV: A segmentation fault occurred in Sage.
This probably occurred because a *compiled* component
of Sage has a bug in it (typically accessing invalid memory)
or is not properly wrapped with _sig_on, _sig_off.
You might want to run Sage under gdb with 'sage -gdb' to debug this.
Sage will now terminate (sorry).
------------------------------------------------------------




On Sep 13, 2:32 pm, Willem Jan Palenstijn <w...@usecode.org> wrote:
> On Tue, Sep 13, 2011 at 06:10:45AM -0700, Michael Rubinstein wrote:
> > Example 2
> > ----------------
>
> > Next thing I tried to do was to embed sage in a c program, by
> > following
> >http://docs.python.org/extending/embedding.html
> > but that gave me errors at runtime.
>
> > For example, the following embed.c progam produced the output/errors at the
> > bottom of this post. Any ideas what's wrong? Any ideas of better ways to call
> > sage from within c or c++?
>
> Some quick googling suggests you may have to call PySys_SetArgv[Ex] (http://docs.python.org/c-api/init.html#PySys_SetArgvEx) to set up sys.argv

Willem Jan Palenstijn

unread,
Sep 13, 2011, 1:39:20 PM9/13/11
to sage-...@googlegroups.com
On Tue, Sep 13, 2011 at 08:46:05AM -0700, Michael Rubinstein wrote:
>
> I tried adding PySys_SetArgv(argc, argv); after Py_Initialize();
> It gets me further but then gives a strange error message:
>
> Loading the Sage library...
>
>
> ------------------------------------------------------------
> Unhandled SIGSEGV: A segmentation fault occurred in Sage.
> This probably occurred because a *compiled* component
> of Sage has a bug in it (typically accessing invalid memory)
> or is not properly wrapped with _sig_on, _sig_off.
> You might want to run Sage under gdb with 'sage -gdb' to debug this.
> Sage will now terminate (sorry).
> ------------------------------------------------------------


I've just tried it here with your embed.c + PySys_SetArgv(argc, argv), and it
works for me when I link against libpython2.6 dynamically:

$ gcc -I$SAGE_LOCAL/include/python2.6 embed.c -lpython2.6 -lm -lutil -lpthread -ldl -o embed
$ ./embed
1+1:
2
Load sage
Factor 2310:


2 * 3 * 5 * 7 * 11

$


This is 64 bit linux with sage 4.7.1rc1.

-Willem Jan

Michael Rubinstein

unread,
Sep 13, 2011, 7:45:58 PM9/13/11
to sage-devel
Thanks! That worked for me too, though I'm not sure how you decided on
the specific
choices of libraries to link to.

Mike

Willem Jan Palenstijn

unread,
Sep 14, 2011, 5:35:02 AM9/14/11
to sage-...@googlegroups.com
On Tue, Sep 13, 2011 at 04:45:58PM -0700, Michael Rubinstein wrote:
> Thanks! That worked for me too, though I'm not sure how you decided on
> the specific choices of libraries to link to.

Good to hear. The libraries are just what I needed to add to get it to link
without errors after starting with the -lpython2.6, by the way.


-Willem Jan

Alexander Dreyer

unread,
Sep 14, 2011, 6:04:06 AM9/14/11
to sage-devel
More generically, you may ask python itself about this, just integrate
the following into you build system:
python -c "from distutils.sysconfig import *; print get_config_vars()
['LIBS']"

My best,
Alexander
Message has been deleted

J. Javan

unread,
Jan 30, 2018, 8:35:45 AM1/30/18
to sage-devel
I can see that you have successfully linked against sage.
I also have a Qt GUI application which needs to do some mathematics in the background.
This application is targeted for windows platforms. I have installed sage from this link.
Could you please guide me on how to link my app with sage?

I'm running your code as below

#include <Python.h>

int main(int argc, char *argv[])
{

    int retVal = 0;
    Py_Initialize();
    PySys_SetArgv(argc, (wchar_t**) argv);
    printf("1+1:\n");
    PyRun_SimpleString("print (1+1)");
    printf("Load sage \n");
    retVal = PyRun_SimpleString("from sage.all import *");
    printf("Factor 2310:\n");
    PyRun_SimpleString("print factor(2310)");
    Py_Finalize();
    return 0;
}

And this gives me the following output:

1+1:
2
Load sage
Traceback (most recent call last):
 
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'sage'
Factor 2310:
 
File "<string>", line 1
   
print factor(2310)
               
^
SyntaxError: invalid syntax
Press <RETURN> to close this window...

The output is clearly stating that sage cannot be found.
This is because I have linked to my locally compiled python static libraries(Actually I have downloaded python source code and linked against it.) which are not aware of sage.

Also I tried to link against python provided in sage installation but I can't find any "python.lib" in it.
I have also set an environment variable $SAGE_LOCAL pointing to "C:\Program Files\SageMath 8.1\runtime\opt\sagemath-8.1\local" but no luck.

Environment:
Qt_v5.9
Windows 7
Python_v3.6.4
Sage_v8.1

Dima Pasechnik

unread,
Jan 31, 2018, 7:20:16 AM1/31/18
to sage-devel
Sage won't run natively on Windows, you need Cygwin. This might explain why it does not work for you.

Erik Bray

unread,
Jan 31, 2018, 9:00:16 AM1/31/18
to sage-devel
Hi,

I saw this mail forwarded to sage-devel, but it appears to be missing
quite a lot of context. What, specifically, is it that you're trying
to do?

To be clear, Sage for Windows is not just a Python module. It's an
entire software suite, including its own Python interpreter. All of
it is complied with Cygwin. You won't be able to "import sage" from
different Python.

If you're trying to build an application that uses Sage internally
somehow you have two choices really--build the entire software inside
Sage's environment (you can do this, for example, from the Sage Shell
which is really a Cygwin shell in the Sage environment). That is,
build all your software in Cygwin, linking with the Python in Sage,
etc. This can be tricky unless you know what you're doing with Sage's
development environment.

Your other alternative is that you can always call Sage's Python from
outside Sage (but again, you'll still have to set a few environment
variables at a minimum), and depending on how Python is integrated
into your software this could mean anything from running the Python
interpreter as a subprocess and communicating with it, to dynamically
linking with the libpython DLL in Sage and running C Python code like
in your example above. Though to be honest I'm not exactly sure if
it's possible to link a Cygwin DLL into a non-Cygwin executable. But I
think maybe it's possible....

Please let me know more about what you're trying to do though and I
can probably be of more help.

Best,
E
> --
> You received this message because you are subscribed to the Google Groups
> "sage-devel" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sage-devel+...@googlegroups.com.
> To post to this group, send email to sage-...@googlegroups.com.
> Visit this group at https://groups.google.com/group/sage-devel.
> For more options, visit https://groups.google.com/d/optout.

J. Javan

unread,
Feb 22, 2018, 5:44:09 AM2/22/18
to sage-devel
Dear Erik,

I highly appreciate you for taking the time and helping people. 
Basically, we have some mathematical problems in a GUI application implemented in Qt-C++ which sage is capable of computing them. This is why we decided to integrate sage in our app.

However, As you mentioned it is a very complex or even impossible task to integrate sage into a windows application since sage is a software suit rather than a python library.

After googling some, I found another project called SageMathCell which provides REST interface to a sage server. I guess this is the best of way achieving what we are looking for. Unless I'm very much mistaken, with SageMathCell we can run all sage scripts with peace of mind. 

As mentioned in this tutorial one should URL encode the sage script and POST it to 
http://{IP address of your SageMathCell server}:8888/service.

This perfectly works however I cannot it get to work for some scripts.

For instance calling the service with below code works:
QNetworkRequest request;
request.setUrl(QUrl("http://192.168.224.130:8888/service"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
arrReqBody = "code=print(1+1)"; // This is the sage script which is put in HTTP body request
arrReqBody = request.url().toPercentEncoding(arrReqBody, "=()[].:,");
QNetworkAccessManager *netMgr = new QNetworkAccessManager();
QObject::connect(netMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(sageReply(QNetworkReply*)));
netMgr->post(request, arrReqBody);
Which returns the result in stdout as shown below:
"{\"execute_reply\": {\"status\": \"ok\", \"execution_count\": 1, \"user_expressions\": {}, \"payload\": []}, \"success\": true, \"stdout\": \"2\\n\"}"

On the other hand, changing sage script to below does not work.

arrReqBody = "code='Y=Polyhedron(vertices=[(0,0,0,0,0,0,0,0),(0,0,0,1,0,1,0,1),(0,0,0,1,0,1,1,1),(0,0,0,1,1,1,0,1)])";
arrReqBody += "for v in Y.inequality_generator():print v'";

Above HTTP body returns below which states that the script has been successfully ran but I've no idea why stdout is missing.

"{\"execute_reply\": {\"status\": \"ok\", \"execution_count\": 1, \"user_expressions\": {}, \"payload\": []}, \"success\": true}"



My best guess is that there is something wrong about the encoding however no luck until now.
I would appreciate it if someone could lend me a hand on this.

Thanks,
Javan

Erik Bray

unread,
Feb 22, 2018, 10:31:46 AM2/22/18
to sage-devel
On Thu, Feb 22, 2018 at 11:44 AM, J. Javan <jafarj...@gmail.com> wrote:
> Dear Erik,
>
> I highly appreciate you for taking the time and helping people.
> Basically, we have some mathematical problems in a GUI application
> implemented in Qt-C++ which sage is capable of computing them. This is why
> we decided to integrate sage in our app.
>
> However, As you mentioned it is a very complex or even impossible task to
> integrate sage into a windows application since sage is a software suit
> rather than a python library.
>
> After googling some, I found another project called SageMathCell which
> provides REST interface to a sage server. I guess this is the best of way
> achieving what we are looking for. Unless I'm very much mistaken, with
> SageMathCell we can run all sage scripts with peace of mind.

I probably wouldn't--depending on what your application does it would
only slow things down to be passing data between two executables over
the HTTP stack. This may be a relatively easy way but there are
betters.

If your application already depends fully on Sage (which, granted, is
a big dependency), then why not build your application in the Sage +
Cygwin environment? There's no reason you couldn't do that, and would
allow you to incorporate the Python interpreter directly into your
application. Additional, perhaps the C++ component of your
application can be refactored into a library, and the GUI component
can use PyQT or a similar library, which would simplify building (so
long as you have no trouble getting PyQT built against Sage's Python).
(Or maybe the C++ component can go away entirely if it's only for the
GUI--either way).

Beyond that, without seeing your code it's hard to comment much, but I
wouldn't overcomplicate things. Again, if Sage is a hard dependency
of your project then you might as well build the project fully in
Sage's runtime environment.
It looks like you have some extra quoting here. You have

arrReqBody="code='...'"

So the 'code' in this case is just a string literal '...' that happens
to contain the actual code you want. AFAICT there's no reason for
those extra single-quotes. Just as guess though.

Best,
E

Dima Pasechnik

unread,
Feb 22, 2018, 11:37:00 AM2/22/18
to sage-devel
Cantor (https://github.com/KDE/cantor) is a KDE frontend to computer algebra systems, including Sagemath.
So this looks similar to what you're after, no?

Abhishek Kesarwani

unread,
Sep 27, 2018, 9:37:26 AM9/27/18
to sage-devel
I am trying to run Example 2: And getting following error. Please help me.
abc@Math-Sans:~/Desktop$ gcc -I/usr/include/python2.7 ABC.c -lpython2.7  -lm -lutil -lpthread -ldl 
abc@Math-Sans:~/Desktop$ ./a.out
1+1:
2
Load sage 
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named sage.all
Factor 2310:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'factor' is not defined

Dima Pasechnik

unread,
Sep 27, 2018, 9:50:14 AM9/27/18
to sage-devel
For starters, you need Sage's python2, so that at its python prompt you can do

>>> from sage.all import *

and this works. Are you already at this point?

Abhishek Kesarwani

unread,
Sep 28, 2018, 1:36:07 PM9/28/18
to sage-devel
Thank you, sir, for replying.  I tried to run it again after Installing
Sage python2, it gives the following error. 

1+1000000000000000000000000000:
1000000000000000000000000001
Load sage 
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named all
abc@Math-Sans:~/Downloads/SageMath$ python 
Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>  from sage.all import * 
  File "<stdin>", line 1
    from sage.all import * 
    ^
IndentationError: unexpected indent

Dima Pasechnik

unread,
Sep 28, 2018, 2:06:42 PM9/28/18
to sage-devel


On Fri, 28 Sep 2018, 18:36 Abhishek Kesarwani, <1907...@gmail.com> wrote:
Thank you, sir, for replying.  I tried to run it again after Installing
Sage python2, it gives the following error. 

What version of Sagemath have you installed?
Are you able to start Python by running

sage --python

Abhishek Kesarwani

unread,
Sep 29, 2018, 2:34:04 AM9/29/18
to sage-devel

No, I am getting this error:

>>> sage --python
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'sage' is not defined

Simon King

unread,
Sep 29, 2018, 2:45:09 AM9/29/18
to sage-...@googlegroups.com
Hi Abhishek,

On 2018-09-29, Abhishek Kesarwani <1907...@gmail.com> wrote:
>
> No, I am getting this error:
>
>>>> sage --python
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> NameError: name 'sage' is not defined

"sage --python" is the command that you should use on the command line
to *start* python (i.e., it is not a command to be used *in* python).

If the reason hasn't yet been explained to you in this thread: Sage has
its own installation of Python, that is totally separate from your
system-wide installation of Python. Hence, your system-wide installation
of Python simply doesn't know that sage exists.

Therefore, you should use Sage's python installation (that you can start
with the command
sage --python
) and there you should be able to use Sage. Example:

$ ./sage --python
Python 2.7.15 (default, Aug 5 2018, 14:15:34)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> from sage.all import ZZ
>>> type(5), type(ZZ(5))
(<type 'int'>, <type 'sage.rings.integer.Integer'>)

Note that the line "from sage.all import ZZ" takes a very long time, and
to my surprise directly doing "from sage.rings.integer_ring import Z as
ZZ" doesn't work.

Best regards,
Simon

memala...@gmail.com

unread,
Sep 29, 2018, 7:24:39 AM9/29/18
to sage-devel

Our Sage version is 8.2. We are getting this error.

abc@Math-Sans:~/Downloads/SageMath$ sage --python
No command 'sage' found, did you mean:
 Command 'page' from package 'tcllib' (universe)
 Command 'save' from package 'atfs' (universe)
 Command 'osage' from package 'graphviz' (main)
sage: command not found

Also

abc@Math-Sans:~/Downloads/SageMath$ python
Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> sage --python
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'sage' is not defined
>>>

Jan Groenewald

unread,
Sep 29, 2018, 7:31:17 AM9/29/18
to sage-devel
Hi

I missed the rest of this thread, but...

On Sat, 29 Sep 2018 at 13:24, <memala...@gmail.com> wrote:

Our Sage version is 8.2. We are getting this error.

abc@Math-Sans:~/Downloads/SageMath$ sage --python

Use

./sage --python

where the ./ indicates the sage command is in that folder you are located in.

For convenience, you can make sage an alias with

echo '/home/abc/Downloads/SageMath/sage' | tee -a /home/abc/.bashrc ; source /home/abc/.bashrc

You can then just type sage in any folder.

Regards,
Jan



--
  .~.
  /V\     Jan Groenewald
 /( )\    www.aims.ac.za
 ^^-^^ 

Reply all
Reply to author
Forward
0 new messages