call SageMath from C

asked 2023-06-12 17:14:52 +0200

cduston gravatar image

updated 2023-06-13 02:04:57 +0200

I wrote a little Graph Theory / Group Theory function in SageMath (using stuff from GAP, mostly), and now I want to call that from a simulation that I have in C. I have worked out how to call Python from C (here, basically: https://docs.python.org/3/extending/e...) but I can't quite get the sage to work. I've tried things like starting the .py file with

#!/usr/local/bin/sage -python

import sage.all

and that got some things running, but it seems like many jobs were being created all at once, and then it just seg faulted. Anyone have experience with this?

[ I will note there is another question just like this on this site: https://ask.sagemath.org/question/541... ....although I already have a Sage script, so I don't want to actually run a notebook, just the script, and then grab some values back into C]

MWE follows....it doesn't work, but this is what's giving me the behavior. Previously, when this was a .py file instead of .sage (and that "import.sage" was missing), it ran fine.

 #include <Python.h>

int main(int argc,char *argv[])
{
float res;
  res=(float)call(2,3);
  printf("Result of Python script: %f\n",res);
}


int call(int int1,int int2){

  long res;
  Py_Initialize();

  /* Two added lines to get the path right */
  PyRun_SimpleString("import sys");
  /*PyRun_SimpleString("import sage.all");*/
  PyRun_SimpleString("sys.path.append(\".\")");

  PyObject* moduleName = PyUnicode_FromString("test_multiply_test");
  PyObject* module = PyImport_Import(moduleName);
  Py_DECREF(moduleName);

  PyObject* functionName = PyObject_GetAttrString(module, "multiply");

  PyObject* args =PyTuple_New(2);
  PyObject* arg1 = PyLong_FromLong(int1);
  PyObject* arg2 = PyLong_FromLong(int2);
  PyTuple_SetItem(args, 0, arg1);
  PyTuple_SetItem(args, 1, arg2);

  PyObject* result = PyObject_CallObject(functionName, args);

  /* Check if the call was successful */
  if (result != NULL) {
    /* Convert the result to a C string */
    res = PyLong_AsLong(result);
    printf("%ld\n", res);

    /* Clean up the result object */
    Py_DECREF(result);
  } else {
    /* Handle the error */
    PyErr_Print();
  }

  Py_DECREF(arg1);
  Py_DECREF(arg2);
  Py_DECREF(args);
  Py_DECREF(result);

  Py_DECREF(functionName);
  Py_DECREF(module);

  Py_Finalize();

  return res;
}

Oh, and the python file is

def multiply(a,b):
    print("Will compute", a, "times", b)
    c = 0
    for i in range(0, a):
        c = c + b
    return c
edit retag flag offensive close merge delete

Comments

Could you provide more details? "That got some things running" sounds promising, but "it seems like many jobs were being created all at once" needs some clarification. Can you provide more of the script that you used?

John Palmieri gravatar imageJohn Palmieri ( 2023-06-12 19:25:18 +0200 )edit

One idea, by the way, is to only import what you need, rather than the whole Sage library.

John Palmieri gravatar imageJohn Palmieri ( 2023-06-12 19:25:48 +0200 )edit

Added MWE...how about this - can I call Py_Initialize(), do those import calls, and then proceed with both C and Python commands without restarting Python? Maybe the problem is this is inside of a big loop, and I'm constantly Initiatlizing and finalizing Python. As you say, maybe just load the stuff from sage I need once.

cduston gravatar imagecduston ( 2023-06-13 02:06:31 +0200 )edit

Just stumbled upon this question while looking for something similar. I've managed to call SageMath functions in Scheme using C/Python API (https://github.com/padawanphysicist/guile-pyffi).

I think that indeed the problem would be calling initialize/finalize inside the function. Have you tried to keep the functions involving initializing/finazing and import modules outside call?

padawanphysicist gravatar imagepadawanphysicist ( 2024-01-02 20:58:57 +0200 )edit