File:  [CENS] / python / pyGiNaC / wrappers / build.py
Revision 1.7: download - view: text, annotated - select for diffs - revision graph
Tue Apr 17 22:39:25 2001 UTC (16 years, 7 months ago) by pearu
Branches: MAIN
CVS tags: HEAD
Fixed bugs. Exposed/checked functions. Started testing framework.

#!/usr/bin/env python
"""

Collects PyGiNaC wrapper files *.py and
creates a Python extension module exposing GiNaC.

This file is part of the PyGiNaC package.
http://cens.ioc.ee/projects/pyginac/

Copyright 2001 Pearu Peterson all rights reserved,
Pearu Peterson <pearu@cens.ioc.ee>          
Permission to use, modify, and distribute this software is given under the
terms of the LGPL.  See http://www.fsf.org

NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
$Revision: 1.7 $
$Date: 2001-04-17 22:39:25 $
Pearu Peterson
"""

__version__ = "$Id: build.py,v 1.7 2001-04-17 22:39:25 pearu Exp $"


import sys,time,os,re
    
def build_ginac_cpp(winput,outfile='ginac.cpp',wrap_dir='',
                    onlydoc=1,onlytest=1,
                    vers='',credits=''):
    docdir = os.path.join('lib','doc')
    docfile = os.path.join(docdir,'__init__.py')
    testfile = os.path.join('test','test_dt.py')
    print 'build_ginac_cpp:\n\twrapper_dir=%s,\n\toutfile=%s\n\tdocfile=%s'%(`wrap_dir`,`outfile`,`docfile`)
    if onlytest:
        print '\tCreating',`testfile`
        fout = open(testfile,'w')
        def fwrite(s,fout=fout):
            fout.write(s+'\n')
        testmatch = re.compile(r'#STARTDOCTEST(?P<teststr>.*)#ENDDOCTEST',re.M|re.S)
        fwrite('''\
import sys,os
from distutils import util
sys.path.insert(0,os.path.abspath(os.path.join("build","lib.%s-%s" % (util.get_platform(),sys.version[0:3]))))
''')
        for f in winput:
            fin = open(os.path.join(wrap_dir,f+'.py'),'r')
            dtext = '\n'.join(testmatch.findall(fin.read()))
            if dtext:
                fout.write(dtext)
            fin.close()
        fwrite('''
def _test():
    import doctest, test_dt
    return doctest.testmod(test_dt)
if __name__ == "__main__":
    _test()
''')
        fout.close()
        return
    if onlydoc:
        print '\tCreating',`docfile`
        fout = open(docfile,'w')
        def fwrite(s,fout=fout):
            fout.write(s+'\n')
        fwrite('''\
"""PyGiNaC class documentation."""

__version__ = "#version#"
__author__ = "Pearu Peterson <pearu@cens.ioc.ee>"
__date__ = "#date#"
__credits__ = """#credits#"""

# This file (ginac/doc/.__init__.py) is auto-generated with pyGiNaC/wrappers/build.py
# Website: http://cens.ioc.ee/projects/pyginac/'''.replace('#version#',vers).replace('#date#',time.asctime(time.localtime())).replace('#credits#',credits))
        
        docmatch = re.compile(r'#STARTPROTO(?P<proto>.*)#ENDPROTO',re.M|re.S)
        for f in ['ex','basic','flags','symbol','numeric','constant',
                  'matrix','relational','lst',
                  'add','mul','power','ncmul','function','indexed',
                  'idx','tensor','expair','exvector','epvector','inifcns']:
            fin = open(os.path.join(wrap_dir,f+'.py'),'r')
            dtext = '\n'.join(docmatch.findall(fin.read()))
            if dtext:
                #fout.write('from %s import *\n'%(f))
                fout.write(dtext)
                #f2 = open(os.path.join(docdir,f+'.py'),'w')
                #f2.write(dtext)
                #f2.close()
            fin.close()
        fout.write('\n')
        fout.close()
        return

    print '\twinput: %s'%(', '.join(winput))
    def getdict(f,flag=1,winput=winput,wrap_dir=wrap_dir):
        class dummy:
            def __getattr__(self,name): return name
        ret = {'winput':winput,'wrapper_dir':wrap_dir,'basic':dummy,
               'relational':dummy,'exprseq':dummy,'expairseq':dummy,
               'tensor':dummy}
        try: execfile(os.path.join(wrap_dir,f+'.py'),globals(),ret)
        except IOError:
            if flag:
                print '\t\tWrapper description file "%s.py" does not exist. Quiting.'%(f)
                sys.exit()
            else:
                print '\t\tWrapper description file "%s.py" does not exist. Skipping.'%(f)
        for k in ['wrapperclass','protos','builder','constructors','defs','implementation','GiNaC_implementation','GiNaC_protos']:
            try: ret[k]
            except KeyError: ret[k]='' 
        for k in ['depends','uses']:
            try: ret[k]
            except KeyError: ret[k]=[]
        return ret


    d = {}
    for f in winput:
        try: d[f]
        except KeyError: d[f] = getdict(f)

    flag = 1
    while flag:
        flag = 0
        for f in d.keys():
            for o in d[f]['depends']:
                try: d[o]
                except KeyError:
                    print '\tAdding dependence',`o`,'to winput list'
                    d[o] = getdict(o)
                    flag = 1
            for o in d[f]['uses']:
                try: d[o]
                except KeyError:
                    print '\tAdding uses',`o`,'to winput list'
                    d[o] = getdict(o,0)
                    flag = 1

    first_round = []
    second_round = []
    for f in d.keys():
        if not d[f]['depends']:
            first_round.append(f)
        else:
            second_round.append(f)
    flag = 1

    while flag:
        l = len(first_round)
        flag = 0
        for i in range(len(second_round)):
            f = second_round[i]
            if f in first_round:
                continue
            fl = 1
            for o in d[f]['depends']:
                if o not in first_round:
                    fl = 0
                    break
            if fl:
                first_round.append(f)
                flag = 1
        if flag and l==len(first_round):
            print '\tBreaking infinite dependence cycle:'
            for f in second_round:
                if f not in first_round:
                    print f,'depends on',[k for k in d[f]['depends'] if k not in first_round]
                    first_round.append(f)
            break
    print '\tDependence sequence:',', '.join(first_round)

    depinput = first_round

    fout = open(outfile,'w')

    print '\tCreating',`outfile`

    def fwrite(s,fout=fout):
        fout.write(s+'\n')

    fwrite('''\
// This file (ginac.cpp) is auto-generated with pyGiNaC/tools/wrappers/build.py
// Date: '''+time.asctime(time.localtime())+'''
// Author: Pearu Peterson <pearu@cens.ioc.ee>
// Website: http://cens.ioc.ee/projects/pyginac/
''')
    for f in depinput:
        fwrite('#define PYGINAC_'+f)
    fwrite('''\
#if 0
#include <cln/complex.h>
#include <cln/real.h>
#include <cln/integer.h>
#else
// Define cln objects explicitly to reduce memory usage during the compilation
// (effect is about 16MB with optimization flag on)
#include <iostream>
#include <cln/intparam.h>
#include <cln/integer_class.h>
namespace cln {
extern const cl_N complex (const cl_R& a, const cl_R& b);
extern sint32 cl_I_to_L (const cl_I& obj);
#if (long_bitsize==32)
  inline long          cl_I_to_long  (const cl_I& x) { return cl_I_to_L(x);  }
#elif (long_bitsize==64)
  inline long          cl_I_to_long  (const cl_I& x) { return cl_I_to_Q(x);  }
#endif
extern const cl_I truncate1 (const cl_R& x);
class cl_print_flags;
extern void print_complex (std::ostream& stream, const cl_print_flags& flags, const cl_N& z);
inline void fprint (std::ostream& stream, const cl_N& x)
{
        extern cl_print_flags default_print_flags;
        print_complex(stream,default_print_flags,x);
}
inline std::ostream& operator<< (std::ostream& stream, const cl_N& x)
{
        fprint(stream,x);
        return stream;
}
}
#endif

#include <ginac/ginac.h>



#if GINACLIB_MAJOR_VERSION == 0 && (GINACLIB_MINOR_VERSION < 8 || (GINACLIB_MINOR_VERSION == 8 && GINACLIB_MICRO_VERSION == 0))
#define GINAC_VERSION_0_8_0_OR_EARLIER
#endif

#if GINACLIB_MAJOR_VERSION == 0 && (GINACLIB_MINOR_VERSION < 8 || (GINACLIB_MINOR_VERSION == 8 && GINACLIB_MICRO_VERSION <= 1))
#define GINAC_VERSION_0_8_1_OR_EARLIER
#endif

#if GINACLIB_MAJOR_VERSION > 0 || (GINACLIB_MINOR_VERSION > 8 || GINACLIB_MINOR_VERSION == 8 && GINACLIB_MICRO_VERSION > 0) 
#define GINAC_VERSION_LATER_THAN_0_8_0
#endif

#include <boost/python/class_builder.hpp>

#define BasicInstance_Check(op) ((!((op)->ob_type == NULL)) && ( \
      (op)->ob_type == (PyTypeObject*)basic_py_class \
      || (op)->ob_type == (PyTypeObject*)numeric_py_class \
      || (op)->ob_type == (PyTypeObject*)symbol_py_class \
      || (op)->ob_type == (PyTypeObject*)constant_py_class \
      || (op)->ob_type == (PyTypeObject*)relational_py_class \
      || (op)->ob_type == (PyTypeObject*)power_py_class \
      || (op)->ob_type == (PyTypeObject*)add_py_class \
      || (op)->ob_type == (PyTypeObject*)mul_py_class \
      || (op)->ob_type == (PyTypeObject*)idx_py_class \
      || (op)->ob_type == (PyTypeObject*)varidx_py_class \
      || (op)->ob_type == (PyTypeObject*)pseries_py_class \
      || (op)->ob_type == (PyTypeObject*)matrix_py_class \
      || (op)->ob_type == (PyTypeObject*)ncmul_py_class \
      || (op)->ob_type == (PyTypeObject*)function_py_class \
      || (op)->ob_type == (PyTypeObject*)indexed_py_class \
      || (op)->ob_type == (PyTypeObject*)clifford_py_class \
      || (op)->ob_type == (PyTypeObject*)color_py_class \
      || (op)->ob_type == (PyTypeObject*)lst_py_class))

#define ExInstance_Check(op) ((!((op)->ob_type == NULL)) && (\
      (op)->ob_type == (PyTypeObject*)ex_py_class))
#define MatrixInstance_Check(op) ((!((op)->ob_type == NULL)) && (\
      (op)->ob_type == (PyTypeObject*)matrix_py_class))
#define RelationalInstance_Check(op) ((!((op)->ob_type == NULL)) && (\
      (op)->ob_type == (PyTypeObject*)relational_py_class))
#define NumericInstance_Check(op) ((!((op)->ob_type == NULL)) && (\
      (op)->ob_type == (PyTypeObject*)numeric_py_class))
#define SymbolInstance_Check(op) ((!((op)->ob_type == NULL)) && (\
      (op)->ob_type == (PyTypeObject*)symbol_py_class))
#define ExpairInstance_Check(op) ((!((op)->ob_type == NULL)) && (\
      (op)->ob_type == (PyTypeObject*)expair_py_class))

#ifdef DEBUG_PYGINAC
#define DEBUG_C(o) cout << o << endl; // debug constructors
#define DEBUG_S(o) cout << o << endl; // debug tostr,torepr methods
#define DEBUG_M(o) cout << o << endl; // debug member functions
#else
#define DEBUG_C(o) 
#define DEBUG_S(o) 
#define DEBUG_M(o) 
#endif

#define EX_TO_BASIC(NAME) \
const GiNaC::NAME & ex_to_##NAME##_w(const GiNaC::ex & e) { \
  if (is_ex_exactly_of_type(e, NAME)) \
    return GiNaC::ex_to_##NAME(e); \
  cout<<"ex_to_"#NAME"_w(";GiNaC::python_repr(cout,e);cout<<")"<<std::endl; \
  PyErr_SetString(PyExc_TypeError, "ex_to_" #NAME "() argument must be ex(" #NAME ")");\
  throw python::error_already_set(); \
} \
inline GiNaC::NAME as_##NAME##_w(python::ref obj) { \
  return NAME##_w(obj); \
}

#define BASIC_DEF(NAME) \
PyObject * NAME##_py_class = NULL; \
class NAME##_w; \
inline GiNaC::NAME as_##NAME##_w(python::ref); \
inline const GiNaC::NAME & ex_to_##NAME##_w(const GiNaC::ex &);

#define BASIC_OPS(NAME) \
NAME##_class.def(&basic_w::op_pos, "__pos__");\
NAME##_class.def(&basic_w::op_neg, "__neg__");\
NAME##_class.def(&basic_w::op_add, "__add__");\
NAME##_class.def(&basic_w::op_sub, "__sub__");\
NAME##_class.def(&basic_w::op_mul, "__mul__");\
NAME##_class.def(&basic_w::op_div, "__div__");\
NAME##_class.def(&basic_w::op_pow, "__pow__");

#if 1
#define UNEX(OBJ) (((const ex_w &)(OBJ)).unex())
#define UNEX_RET python::ref
#else
//#define UNEX(OBJ) (OBJ)
//#define UNEX_RET GiNaC::ex
#endif

namespace GiNaC {

#ifdef PYGINAC_function
#define PYGINAC_pyfunc
// Special object for a GiNaC::function argument indicating that the function
// is defined in Python. It holds serial.
const unsigned TINFO_pyfunc = 0x000c1234U;
class pyfunc : public basic {
  GINAC_DECLARE_REGISTERED_CLASS(pyfunc, basic)
public:
  pyfunc(unsigned ser) : inherited(TINFO_pyfunc) { this->serial = ser; }
  unsigned get_serial(void) const { return this->serial; }
  ex derivative(const symbol & s) const { return _ex0(); }
private:
  unsigned serial;
};
GINAC_IMPLEMENT_REGISTERED_CLASS(pyfunc, basic)
pyfunc::pyfunc() : inherited(TINFO_pyfunc) {} 
void pyfunc::destroy(bool call_parent) { if (call_parent) inherited::destroy(call_parent); }
void pyfunc::copy(const pyfunc & other) { inherited::copy(other); this->serial = other.get_serial(); }
void pyfunc::archive(archive_node &n) const { inherited::archive(n); }
pyfunc::pyfunc(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) {}
ex pyfunc::unarchive(const archive_node &n, const lst &sym_lst) {
  return (new pyfunc(n, sym_lst))->setflag(status_flags::dynallocated); }
int pyfunc::compare_same_type(const basic & other) const {
  const pyfunc &o = static_cast<const pyfunc &>(other);
  if (this->serial == o.get_serial()) return 0;
  if (this->serial < o.get_serial()) return -1;
  return 1;
}
inline const pyfunc & ex_to_pyfunc(const ex & e) {
  return static_cast<const pyfunc &>(*e.bp);
}
#endif // PYGINAC_function

} // namespace GiNaC


#define PseudoIndex -1
#define RubberIndex -2
#define SingleIndex -3
extern "C" {
  int parse_subindex(PyObject *op, int *step_size, int *n_steps, int max);
}

namespace python = boost::python;
namespace {

PyObject * ex_py_class = NULL;
PyObject * basic_py_class = NULL;
PyObject * exlist_py_class = NULL;
PyObject * expair_py_class = NULL;
PyObject * exvector_py_class = NULL;
PyObject * epvector_py_class = NULL;

PyObject * tensor_py_class = NULL;
PyObject * diracgamma_py_class = NULL;
PyObject * diracone_py_class = NULL;
PyObject * su3d_py_class = NULL;
PyObject * su3f_py_class = NULL;
PyObject * su3one_py_class = NULL;
PyObject * su3t_py_class = NULL;
PyObject * tensdelta_py_class = NULL;
PyObject * tensepsilon_py_class = NULL;
PyObject * tensmetric_py_class = NULL;
PyObject * minkmetric_py_class = NULL;

class ex_w;
class basic_w;
class exlist_w;
class expair_w;
class exvector_w;
class epvector_w;

inline GiNaC::ex as_ex_w(python::ref);
inline GiNaC::epvector as_epvector_w(python::ref);
inline GiNaC::exvector as_exvector_w(python::ref);

BASIC_DEF(numeric)
BASIC_DEF(constant)
BASIC_DEF(symbol)
BASIC_DEF(power)
BASIC_DEF(relational)
BASIC_DEF(lst)
BASIC_DEF(add)
BASIC_DEF(mul)
BASIC_DEF(idx)
BASIC_DEF(varidx)
BASIC_DEF(pseries)
BASIC_DEF(matrix)
BASIC_DEF(ncmul)
BASIC_DEF(function)
BASIC_DEF(indexed)
BASIC_DEF(clifford)
BASIC_DEF(color)

#ifdef PYGINAC_numeric
static python::tuple numeric_coerce(const GiNaC::numeric & left, python::ref right);
#endif
#ifdef PYGINAC_matrix
static python::tuple matrix_coerce(const GiNaC::matrix & left, python::ref right);
#endif

// Holds evaluation objects for GiNaC::constant objects defined in Python
//std::map<unsigned, python::ref> constant_w_cache; // see python_repr.cpp


// Holds serial numbers of GiNaC::function objects defined in Python
std::map<unsigned, unsigned> function_w_ser_cache;



}

namespace GiNaC {


std::map<unsigned, python::ref> & constant_w_cache(void);

void python_repr(std::ostream &, const ex &);
void python_repr(std::ostream &, const expair &);
void python_repr(std::ostream &, const epvector &);
void python_repr(std::ostream &, const exvector &);
void python_repr(std::ostream &, const matrix &);
void python_repr(std::ostream &, const pseries &);
void python_repr(std::ostream &, const indexed &);
void python_repr(std::ostream &, const function &);

void python_str(std::ostream &, const expair &, unsigned level=0);
void python_str(std::ostream &, const epvector &, unsigned level=0);
void python_str(std::ostream &, const exvector &, unsigned level=0);
void python_str(std::ostream &, const ex &, unsigned level=0);

''')
    for f in depinput:
        fwrite(d[f]['GiNaC_protos'])
    fwrite('''
}
namespace {
''')
    for f in depinput:
        fwrite(d[f]['wrapperclass'])
    for f in depinput:
        fwrite(d[f]['protos'])
    fwrite('''
}
BOOST_PYTHON_MODULE_INIT(_ginac)
{
    try
    {
        python::module_builder this_module("_ginac");
''')

    for f in depinput:
        fwrite(d[f]['builder'])

    for f in depinput:
        fwrite(d[f]['constructors'])

    for f in depinput:
        fwrite(d[f]['defs'])

    fwrite('''
    }
    catch(...)
    {
        python::handle_exception();
    }
}

namespace GiNaC {
''')
    for f in depinput:
        fwrite(d[f]['GiNaC_implementation'])
    fwrite('''
}

namespace {
''')
    for f in depinput:
        fwrite(d[f]['implementation'])
    fwrite('''
}
''')

    fout.close()



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