Annotation of python/pyGiNaC/wrappers3/function_py.cpp, revision 1.5

1.1       pearu       1: /*
                      2: # This file is part of the PyGiNaC package.
                      3: # http://cens.ioc.ee/projects/pyginac/
                      4: #
1.5     ! pearu       5: # $Revision: 1.4 $
        !             6: # $Id: function_py.cpp,v 1.4 2001/04/27 11:36:59 pearu Exp $
1.1       pearu       7: #
                      8: # Copyright 2001 Pearu Peterson all rights reserved,
                      9: # Pearu Peterson <pearu@cens.ioc.ee>
                     10: # Permission to use, modify, and distribute this software is given under the
                     11: # terms of the LGPL.  See http://www.fsf.org
                     12: #
                     13: # NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
                     14: #
                     15: */
                     16: /*DT
                     17:   Function
                     18:   ------
                     19: 
                     20:   To create a GiNaC function, use build_function:
                     21:   >>> from ginac import build_function
                     22: 
                     23:   To make a function with zero parameters:
                     24:   >>> foo = build_function('foo')
                     25:   >>> foo()
                     26:   foo()
                     27:   >>> print foo()
                     28:   foo()
                     29: 
                     30:   To make a function with one parameter:
                     31:   >>> foo = build_function('foo',nofargs=1)
                     32:   >>> foo(3)
                     33:   foo(numeric('3'))
                     34:   >>> print foo(3)
                     35:   foo(3)
                     36: 
                     37:   etc. Maximum number of parameters is 12:
                     38:   >>> bar = build_function('bar',nofargs=12)
                     39:   >>> print bar(1,2,3,4,5,6,7,8,9,0,1,2)
                     40:   bar(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2)
                     41:   >>> bar2 = build_function('bar2',nofargs=13)
                     42:   Traceback (most recent call last):
                     43:   ...
                     44:   NotImplementedError: _build_function() first argument must be less than 12
                     45: 
                     46:   An exception is raised, when function is used with the wrong
                     47:   number of parameters:
                     48:   >>> foo(3,4)
                     49:   Traceback (most recent call last):
                     50:   ...
                     51:   TypeError: function foo() takes exactly 1 argument (2 given)
                     52: 
                     53:   For automatic evaluation use user-defined evaluation function:
                     54:   >>> from ginac import numeric
                     55:   >>> def gun_eval(x):
                     56:   ...     if x.is_negative(): return 0
                     57:   ...     return gun(x,hold=1)
                     58:   >>> gun = build_function('gun',eval_f=gun_eval)
                     59:   >>> print gun(-1), gun(3)
                     60:   0 gun(3)
                     61: 
                     62:   Important:
                     63:   Note the use of the `hold' keyword which stops futher automatic
                     64:   evaluation of the function. You **MUST** use it when no more
                     65:   evaluation is desired. Otherwise the evaluation function is called
                     66:   recursively until something nasty happens (recursion depth is
                     67:   reached, out of memory error,...).
                     68: 
                     69:   Similary, you can submit functions for numerical evaluation (evalf_f,
                     70:   must take nofargs arguments), for derivative (derivative_f, must take
                     71:   nofargs+1 arguments), and for series expansion (series_f, must take
                     72:   nofargs+3 arguments). For example,
                     73:   >>> def sun_derivative(x,i):
                     74:   ...     # return derivative in respect to the i-th parameter.
                     75:   ...     assert int(i)==0
                     76:   ...     if x.is_negative(): return 0
                     77:   ...     return x*sun(x)
                     78:   >>> sun = build_function('sun', derivative_f=sun_derivative)
                     79:   >>> print sun(3)
                     80:   sun(3)
                     81:   >>> from ginac import symbol
                     82:   >>> z = symbol('z')
                     83:   >>> print sun(z).diff(z)
1.2       pearu      84:   z * sun(z)
1.1       pearu      85:   >>> print sun(z).diff(z,2)
1.2       pearu      86:   z ** 2 * sun(z) + sun(z)
1.1       pearu      87: 
                     88:   Note that build_function is able to determine the number of parameters
                     89:   automatically from the given functions eval_f, evalf_f, derivative_f, series_f.
                     90:   But in some occasions it is impossible. Therefore, giving the nofargs explicitly
                     91:   is always recommended.
                     92: 
                     93:   Auxiliary functions:
                     94:   >>> from ginac import is_function, sin
                     95:   >>> is_function(sin(2))
                     96:   1
                     97:   >>> sin(2).get_name()
                     98:   'sin'
                     99: */
                    100: 
1.4       pearu     101: /*F_DT build_function(name,texname=None,eval_f=None,evalf_f=None,derivative_f=None,series_f=None,nofargs=None)
                    102:   Construct symbolic function with a name `name'.
                    103: 
                    104:   Optional arguments:
                    105:   texname      - LaTeX string;
                    106:   nofargs      - the number of arguments to a function (if not specified,
                    107:                  build_function tries to establish `nofargs' from functions `eval',
                    108:                 `evalf', `derivative', `series'. If that fails, 12 is set.);
                    109:   eval_f       - eval_f(*args) is used for automatic non-interruptive symbolic
                    110:                  evaluation;
                    111:   evalf_f      - evalf_f(*args) is used for numeric evaluation;
                    112:   derivative_f - derivative_f(*args,i) is used for computing
                    113:                  the 1st derivative with respect to `i'-th argument (i>=0);
                    114:   series_f     - series_f(*args,rel,order,opts = 0) is used for computing
                    115:                  the truncated series expansion around a point `rhs(rel)'
                    116:                  with respect to variable `lhs(rel)'. `order' is the truncation
                    117:                  order.
                    118:  */
                    119: 
1.1       pearu     120: #define PYGINAC_CB_FUNC_PROTO(name,num,ARGS) GiNaC::ex name##_func##num##_w ARGS
                    121: 
                    122: #ifdef PYGINAC_DEFS
                    123: this_module.def(&function_g, "_function");
                    124: this_module.def(&pyfunc_1, "_pyfunc");
                    125: this_module.def(&ex::is_function, "is_function");
                    126: this_module.def(&return_false, "is_function");
                    127: ex_class.def(&ex::is_function, "is_function");
1.5     ! pearu     128: ex_class.def(&ex::get_serial, "get_serial");
1.1       pearu     129: this_module.def_raw(&build_function, "_build_function");
                    130: #else
                    131: #ifdef PYGINAC_EX_PROTOS
                    132: #define PYGINAC_PROTOS
                    133: #endif
                    134: #ifdef PYGINAC_PROTOS
                    135: #ifdef PYGINAC_EX_PROTOS
                    136: bool is_function(void) const;
1.5     ! pearu     137: unsigned get_serial(void) const;
1.1       pearu     138: #else // PYGINAC_EX_PROTOS
                    139: #include "pyfunc.hpp"
                    140: class wrap_function: public GiNaC::function {
                    141: public:
                    142:   static std::vector<GiNaC::function_options>& registered_functions (void) {
                    143:     return GiNaC::function::registered_functions();
                    144:   }
                    145: };
                    146: std::map<unsigned, py::ref> function_w_eval_cache;
                    147: std::map<unsigned, py::ref> function_w_evalf_cache;
                    148: std::map<unsigned, py::ref> function_w_derivative_cache;
                    149: std::map<unsigned, py::ref> function_w_series_cache;
                    150: std::map<unsigned, unsigned> function_w_ser_cache;
                    151: unsigned build_function(PyObject * args, PyObject * kws);
                    152: #include "function_py_subs.cpp"
                    153: //GiNaC::ex function_g(unsigned ser, const GiNaC::exvector & v);
                    154: GiNaC::ex function_g(unsigned ser, bool hold, const GiNaC::exvector & v);
                    155: GiNaC::ex pyfunc_1(unsigned);
                    156: BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
                    157: GiNaC::function from_python (PyObject* o, py::type<const GiNaC::function &>);
                    158: BOOST_PYTHON_END_CONVERSION_NAMESPACE
                    159: #endif // !PYGINAC_EX_PROTOS
                    160: #else  // PYGINAC_PROTOS
                    161: BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
                    162: GiNaC::function from_python (PyObject* o, py::type<const GiNaC::function &>) {
                    163:   if (ExInstance_Check(o)) {
                    164:     GiNaC::ex e = from_python(o, py::type<const GiNaC::ex &>());
                    165:     if (is_ex_exactly_of_type(e, function))
                    166:       return ex_to_function(e);
                    167:   }
1.3       pearu     168:   PYGINAC_FROMPYTHON_TYPEERROR(function,ex(function));
1.1       pearu     169: }
                    170: BOOST_PYTHON_END_CONVERSION_NAMESPACE
                    171: /*F_DT is_function(obj)
                    172:   Check if `obj' is function.
                    173: */
                    174: /*M_DT is_function(self)
                    175:   Check if object is function.
                    176: */
                    177: bool ex::is_function(void) const { return is_ex_exactly_of_type(*this, function); }
                    178: /*F_DT _build_function(nofargs,name,texname=None,eval=None,evalf=None,derivative=None,series=None)
                    179:   Build GiNaC function with Python eval,evalf,derivative,series
                    180:   callback functions.         
                    181:   Return the serial number of constructed function.
                    182:   Used internally. See build_function().
                    183: */
                    184: unsigned build_function(PyObject * args, PyObject * kws) {
                    185:   unsigned ser;
                    186:   unsigned ser1 = wrap_function::registered_functions().size();
                    187:   PyObject * name_py = Py_None;
                    188:   PyObject * texname_py = Py_None;
                    189:   PyObject * nofargs_py = Py_None;
                    190:   PyObject * eval_py = Py_None;
                    191:   PyObject * evalf_py = Py_None;
                    192:   PyObject * derivative_py = Py_None;
                    193:   PyObject * series_py = Py_None;
                    194:   static char *kwlist[] = {"nofargs","name","texname",
                    195:                           "eval","evalf","derivative","series",NULL};
                    196:   if (!PyArg_ParseTupleAndKeywords(args,kws,"OO|OOOOO:_ginac._build_function",kwlist,
                    197:                                   &nofargs_py, &name_py, &texname_py, &eval_py,
                    198:                                   &evalf_py, &derivative_py, &series_py))
                    199:     throw py::error_already_set();
                    200:   if (!PyInt_Check(nofargs_py)) {
                    201:     PyErr_SetString(PyExc_TypeError,"_build_function() first argument must be an int");
                    202:     throw py::error_already_set();
                    203:   }
                    204:   if (!PyString_Check(name_py)) {
                    205:     PyErr_SetString(PyExc_TypeError,"_build_function() second argument must be a string");
                    206:     throw py::error_already_set();
                    207:   }
                    208:   GiNaC::function_options opt;
                    209:   opt = opt.overloaded(-1);
                    210:   if (texname_py == Py_None)
                    211:     opt = opt.set_name(PyString_AsString(name_py));
                    212:   else {
                    213:     if (!PyString_Check(texname_py)) {
                    214:       PyErr_SetString(PyExc_TypeError,"_build_function() `texname' keyword argument must be a string");
                    215:       throw py::error_already_set();
                    216:     }
                    217:     opt = opt.set_name(PyString_AsString(name_py),PyString_AsString(texname_py));
                    218:   }
                    219:   int nofargs = PyInt_AsLong(nofargs_py);
                    220:   if (nofargs>12 || nofargs<0) {
                    221:     PyErr_SetString(PyExc_NotImplementedError,"_build_function() first argument must be less than 12");
                    222:     throw py::error_already_set();
                    223:   }
                    224:   opt.test_and_set_nparams(nofargs+1);
                    225: #define PYGINAC_BUILDFUNC_SUB(eval) \
                    226:   if (!(eval##_py == Py_None)) { \
                    227:     if (!PyCallable_Check(eval##_py)) { \
                    228:       PyErr_SetString(PyExc_TypeError,"_build_function() '"#eval"' keyword argument must be callable");\
                    229:       throw py::error_already_set(); \
                    230:     } \
                    231:     switch (nofargs) { \
                    232:     case 0: opt = opt.eval##_func(eval##_func0_w); break; \
                    233:     case 1: opt = opt.eval##_func(eval##_func1_w); break; \
                    234:     case 2: opt = opt.eval##_func(eval##_func2_w); break; \
                    235:     case 3: opt = opt.eval##_func(eval##_func3_w); break; \
                    236:     case 4: opt = opt.eval##_func(eval##_func4_w); break; \
                    237:     case 5: opt = opt.eval##_func(eval##_func5_w); break; \
                    238:     case 6: opt = opt.eval##_func(eval##_func6_w); break; \
                    239:     case 7: opt = opt.eval##_func(eval##_func7_w); break; \
                    240:     case 8: opt = opt.eval##_func(eval##_func8_w); break; \
                    241:     case 9: opt = opt.eval##_func(eval##_func9_w); break; \
                    242:     case 10: opt = opt.eval##_func(eval##_func10_w); break; \
                    243:     case 11: opt = opt.eval##_func(eval##_func11_w); break; \
                    244:     case 12: opt = opt.eval##_func(eval##_func12_w); break; \
                    245:     default: \
                    246:       PyErr_SetString(PyExc_RuntimeError,"_build_function() failure ("#eval" nofargs bug)"); \
                    247:       throw py::error_already_set(); \
                    248:     } \
                    249:     Py_INCREF(eval##_py); \
                    250:     function_w_##eval##_cache[ser1] = py::ref(eval##_py); \
                    251:   }
                    252: 
                    253:   PYGINAC_BUILDFUNC_SUB(eval);
                    254:   PYGINAC_BUILDFUNC_SUB(evalf);
                    255:   PYGINAC_BUILDFUNC_SUB(derivative);
                    256:   PYGINAC_BUILDFUNC_SUB(series);
                    257: 
                    258:   ser = wrap_function::register_new(opt);
                    259:   if (ser != ser1) {
                    260:     PyErr_SetString(PyExc_RuntimeError, "_build_function() mismatch of function serial numbers");
                    261:     throw py::error_already_set();
                    262:   }
                    263:   function_w_ser_cache[ser]=ser;
                    264:   return ser;
                    265: }
                    266: 
                    267: #define PYGINAC_CB_FUNC(name,num,ARGS,num2,setitem) \
                    268: PYGINAC_CB_FUNC_PROTO(name,num,ARGS) { \
                    269:   py::tuple args(num2); \
                    270:   if (!is_ex_exactly_of_type(ser,pyfunc)) { \
                    271:     PyErr_SetString(PyExc_RuntimeError,#name "_func"#num "() last argument must be ex(pyfunc)"); \
                    272:     throw py::error_already_set(); \
                    273:   } \
                    274:   unsigned ser_ = GiNaC::ex_to_pyfunc(ser).get_serial(); \
                    275:   const std::map<unsigned, py::ref>::const_iterator viter = function_w_##name##_cache.find(ser_); \
                    276:   if (viter==function_w_##name##_cache.end()) { \
                    277:     std::ostrstream os; \
                    278:     os << #name "_func"#num "() failed to find "#name " function in cache "; \
                    279:     os << "(ser_="<<ser_<<")" << std::endl; \
                    280:     PyErr_SetString(PyExc_RuntimeError,os.str()); \
                    281:     throw py::error_already_set(); \
                    282:   } \
                    283:   setitem \
                    284:   PyObject * ret = NULL; \
                    285:   ret = PyObject_CallObject(viter->second.get(), args.get()); \
                    286:   if (ret==NULL) \
                    287:     throw py::error_already_set(); \
                    288:   return ex_from_ref(ret); \
                    289: }
                    290: 
                    291: #include "function_py_subs.cpp"
                    292: 
                    293: /*F_DT _function(ser,hold,seq)
                    294:   Return image of a function with serial number `ser' and
                    295:   arguments `seq'. Last item in `seq' must be ex(pyfunc) object.
                    296:   Used internally.
                    297: */
                    298: GiNaC::ex function_g(unsigned ser, bool hold, const GiNaC::exvector & v) {
                    299:   unsigned l = v.size();
                    300:   if (wrap_function::registered_functions().size() <= ser) {
                    301:     PyErr_SetString(PyExc_TypeError,"_function() invalid serial argument (out of bounds)");
                    302:     throw py::error_already_set();
                    303:   }
                    304:   unsigned el = wrap_function::registered_functions()[ser].get_nparams();
                    305:   if (el != l) {
                    306:     std::ostrstream os;
1.3       pearu     307:     os << "_function(ser="<<ser<<") invalid number of parameters (expected "<<el<<", got "<<l<<")" << std::ends;
1.1       pearu     308:     PyErr_SetString(PyExc_TypeError,os.str());
                    309:     throw py::error_already_set();
                    310:   }
1.5     ! pearu     311:   const std::map<unsigned, unsigned>::const_iterator viter = function_w_ser_cache.find(ser);
        !           312:   if (viter!=function_w_ser_cache.end() && !is_ex_exactly_of_type(v[l-1], pyfunc)) {
1.3       pearu     313:     std::ostrstream os;
1.5     ! pearu     314:     os << "_function(ser="<<ser<<") last argument must be ex(pyfunc) of user-defined fun"<<std::ends;
1.3       pearu     315:     PyErr_SetString(PyExc_TypeError,os.str());
1.1       pearu     316:     throw py::error_already_set();
                    317:   }
                    318:   if (hold)
                    319:     return GiNaC::function(ser, v, true).hold();
                    320:   return GiNaC::function(ser, v, true);
                    321: }
                    322: 
                    323: /*F_DT _pyfunc(ser)
                    324:   Return ex(pyfunc) holding serial number `ser'.
                    325:   Used internally.
                    326: */
                    327: GiNaC::ex pyfunc_1(unsigned ser) {
                    328:   return GiNaC::pyfunc(ser);
1.5     ! pearu     329: }
        !           330: 
        !           331: /*M_DT get_serial(self)
        !           332:   Return serial number of a function.
        !           333:   `self' must be ex(function).
        !           334:  */
        !           335: unsigned ex::get_serial(void) const {
        !           336:   if (is_function())
        !           337:     return ex_to_function(*this).get_serial();
        !           338:   PyErr_SetString(PyExc_NotImplementedError, "ex.get_serial() can be used only for ex(function)");
        !           339:   throw py::error_already_set();
1.1       pearu     340: }
                    341: 
                    342: #endif // !PYGINAC_PROTOS
                    343: #endif // !PYGINAC_DEFS
                    344: 
                    345: 
                    346: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>