diff options
Diffstat (limited to 'numpy/f2py')
147 files changed, 23895 insertions, 0 deletions
diff --git a/numpy/f2py/BUGS.txt b/numpy/f2py/BUGS.txt new file mode 100644 index 000000000..ee08863bb --- /dev/null +++ b/numpy/f2py/BUGS.txt @@ -0,0 +1,55 @@ +December 1, 2002: + +C FILE: STRING.F + SUBROUTINE FOO + END +C END OF FILE STRING.F +does not build with + f2py -c -m string string.f +Cause: string is mapped to string_bn +************************************************************************** +August 16, 2001: +1) re in Python 2.x is **three** times slower than the re in Python 1.5. +************************************************************************** +HP-UX B.10.20 A 9000/780: +Fortran function returning character*(*) (id=7) ... failed(core dump) +Fortran function returning logical*8 (id=21) ... expected .true. but got 0 +Callback function returning real (id=45) ... expected 34.56 but got 14087495680.0 +Callback function returning real*4 (id=46) ... expected 34.56 but got 14087495680.0 +Callback function returning logical*8 (id=55) ... expected .true. but got 0 + C compiler: gcc ('gcc 2.x.x' 2.95.2) (from .f2py_get_compiler_CC) + Fortran compiler: g77 ('g77 2.x.x' 2.95.2) (from .f2py_get_compiler_FC) + Linker: ld ('HP-UX ld' 92453-07 linker linker ld B.10.24 961204) (from .f2py_get_compiler_LD) +************************************************************************** +Linux 2.2.13-0.9 #1 Thu Dec 9 17:03:57 EST 1999 alpha unknown: +Fortran function returning character*(*) (id=7) ... expected 'abcdefgh' but got 'abcdefgh \201' (o?k) +Callback function returning complex (id=48) ... failed(core dump) + Trying with -DF2PY_CB_RETURNCOMPLEX ... failed(core dump) +Callback function returning complex*8 (id=49) ... failed(core dump) + Trying with -DF2PY_CB_RETURNCOMPLEX ... failed(core dump) +Callback function returning complex*16 (id=50) ... failed(core dump) + Trying with -DF2PY_CB_RETURNCOMPLEX ... failed(core dump) + C compiler: cc ('Compaq C' V6.2-002) (from .f2py_get_compiler_CC) + Fortran compiler: fort ('Compaq Fortran' V1.0-920) (from .f2py_get_compiler_FC) + Linker: fort ('Compaq Fortran' V1.0-920) (from .f2py_get_compiler_LD) +************************************************************************** +Linux 2.2.14-15mdk #1 Tue Jan 4 22:24:20 CET 2000 i686 unknown: +Callback function returning logical*8 (id=55) ... failed + C compiler: cc ('gcc 2.x.x' 2.95.2) + Fortran compiler: f90 ('Absoft F90' 3.0) + Linker: ld ('GNU ld' 2.9.5) +************************************************************************** +IRIX64 6.5 04151556 IP30: +Testing integer, intent(inout) ...failed # not f2py problem +Testing integer, intent(inout,out) ...failed +Testing integer*1, intent(inout) ...failed +Testing integer*1, intent(inout,out) ...failed +Testing integer*8, intent(inout) ...failed +Testing integer*8, intent(inout,out) ...failed +cc-1140 cc: WARNING File = genmodule.c, Line = 114 + A value of type "void *" cannot be used to initialize an entity of type + "void (*)()". + {"foo",-1,{-1},0,(char *)F_FUNC(foo,FOO),(void *)gen_foo,doc_gen_foo}, + C compiler: cc ('MIPSpro 7 Compilers' 7.30) + Fortran compiler: f77 ('MIPSpro 7 Compilers' 7.30) + Linker: ld ('Linker for MIPSpro 7 Compilers' 7.30.) diff --git a/numpy/f2py/Makefile b/numpy/f2py/Makefile new file mode 100644 index 000000000..91c199f99 --- /dev/null +++ b/numpy/f2py/Makefile @@ -0,0 +1,173 @@ +# Makefile for f2py2e +# +# Use GNU make for making. +# $Revision: 1.46 $ +# $Date: 2005/01/30 17:22:55 $ +# Pearu Peterson <pearu@ioc.ee> + +PYTHON=python +MAJOR=2 +F2PY2E_CVSROOT=:pserver:anonymous@cens.ioc.ee:/home/cvs +SCIPY_CVSROOT=:pserver:anonymous@scipy.org:/home/cvsroot + +UPLOADCMD = scp -r +UPLOADDIR = pearu@kev.ioc.ee:/net/cens/home/www/unsecure/projects/f2py2e/ + +REV=`python -c 'from __version__ import *;print version'` +SCIPY_DISTUTILS_REV=`cd scipy_distutils && $(PYTHON) -c 'from scipy_distutils_version import *;print scipy_distutils_version' && cd ..` + +SRC_FILES = F2PY-$(MAJOR)-latest.tar.gz scipy_distutils-latest.tar.gz F2PY-$(MAJOR)-latest.win32.exe scipy_distutils-latest.win32.exe + +HTML_FILES = index.html FAQ.html HISTORY.html THANKS.html TESTING.html OLDNEWS.html +FAQ_DEPS = simple.f pytest.py pyforttest.pyf simple_session.dat +README_DEPS = hello.f +UG_FILES = index.html f2py_usersguide.pdf +UG_FILES_DEP = $(shell cd docs/usersguide && ls *.{f,f90,dat,pyf,py}) + +WWW_SRC_FILES = $(SRC_FILES:%=upload/www/$(MAJOR).x/%) +WWW_WEB_FILES = $(HTML_FILES:%=upload/www/%) $(README_DEPS:%=upload/www/%) +WWW_UG_FILES = $(UG_FILES:%=upload/www/usersguide/%) $(UG_FILES_DEP:%=upload/www/usersguide/%) + +TMP_WEB_FILES = $(HTML_FILES:%=upload/tmp/%) $(README_DEPS:%=upload/tmp/%) + +############################################################################## + +all: + @echo "Use 'make install' to install f2py" + @echo "Use 'make generate' to build f2py docs to upload/tmp" +install: + $(PYTHON) setup.py install +test: + cd tests && $(PYTHON) run_all.py + +############################################################################## +# Create F2PY tar-balls +############################################################################## +f2py2e: + test -d f2py2e && (cd f2py2e && cvs -d $(F2PY2E_CVSROOT) -z7 update -Pd && cd -) || cvs -d $(F2PY2E_CVSROOT) checkout f2py2e + +upload/tmp/$(MAJOR).x/F2PY-$(MAJOR)-latest.tar.gz: f2py2e + cd f2py2e && python setup.py sdist -f + mkdir -p upload/tmp/$(MAJOR).x + cp f2py2e/dist/F2PY-$(REV).tar.gz upload/tmp/$(MAJOR).x + ln -sf F2PY-$(REV).tar.gz F2PY-$(MAJOR)-latest.tar.gz + mv F2PY-$(MAJOR)-latest.tar.gz upload/tmp/$(MAJOR).x +upload/tmp/$(MAJOR).x/F2PY-$(MAJOR)-latest.win32.exe: f2py2e + cd f2py2e && python setup.py bdist_wininst + mkdir -p upload/tmp/$(MAJOR).x + cp f2py2e/dist/F2PY-$(REV).win32.exe upload/tmp/$(MAJOR).x + ln -sf F2PY-$(REV).win32.exe F2PY-$(MAJOR)-latest.win32.exe + mv F2PY-$(MAJOR)-latest.win32.exe upload/tmp/$(MAJOR).x +f2py2e_latest: upload/tmp/$(MAJOR).x/F2PY-$(MAJOR)-latest.tar.gz upload/tmp/$(MAJOR).x/F2PY-$(MAJOR)-latest.win32.exe + +############################################################################## +# Create Scipy_distutils tar-balls +############################################################################## + +scipy_distutils: + test -d scipy_distutils && (cd scipy_distutils && cvs -d $(SCIPY_CVSROOT) -z7 update -Pd && cd -) || cvs -d $(SCIPY_CVSROOT) checkout scipy_distutils + +upload/tmp/$(MAJOR).x/scipy_distutils-latest.tar.gz: scipy_distutils + cd scipy_distutils && python setup.py sdist -f + mkdir -p upload/tmp/$(MAJOR).x + cp scipy_distutils/dist/scipy_distutils-$(SCIPY_DISTUTILS_REV).tar.gz upload/tmp/$(MAJOR).x + ln -sf scipy_distutils-$(SCIPY_DISTUTILS_REV).tar.gz scipy_distutils-latest.tar.gz + mv scipy_distutils-latest.tar.gz upload/tmp/$(MAJOR).x +upload/tmp/$(MAJOR).x/scipy_distutils-latest.win32.exe: scipy_distutils + cd scipy_distutils && python setup.py bdist_wininst + mkdir -p upload/tmp/$(MAJOR).x + cp scipy_distutils/dist/scipy_distutils-$(SCIPY_DISTUTILS_REV).win32.exe upload/tmp/$(MAJOR).x + ln -sf scipy_distutils-$(SCIPY_DISTUTILS_REV).win32.exe scipy_distutils-latest.win32.exe + mv scipy_distutils-latest.win32.exe upload/tmp/$(MAJOR).x + +scipy_distutils_latest: upload/tmp/$(MAJOR).x/scipy_distutils-latest.tar.gz upload/tmp/$(MAJOR).x/scipy_distutils-latest.win32.exe + +latest: f2py2e_latest scipy_distutils_latest + +############################################################################## +# Upload files. +############################################################################## + +upload/www/$(MAJOR).x/F2PY-$(MAJOR)-latest.tar.gz: upload/tmp/$(MAJOR).x/F2PY-$(MAJOR)-latest.tar.gz + -mkdir -p `dirname $@` + cp -P upload/tmp/$(MAJOR).x/F2PY-{$(MAJOR)-latest,$(REV)}.tar.gz upload/www/$(MAJOR).x + $(UPLOADCMD) upload/tmp/$(MAJOR).x/F2PY-{$(MAJOR)-latest,$(REV)}.tar.gz $(UPLOADDIR)/$(MAJOR).x/ +upload/www/$(MAJOR).x/scipy_distutils-latest.tar.gz: upload/tmp/$(MAJOR).x/scipy_distutils-latest.tar.gz + -mkdir -p `dirname $@` + cp -P upload/tmp/$(MAJOR).x/scipy_distutils-{latest,$(SCIPY_DISTUTILS_REV)}.tar.gz upload/www/$(MAJOR).x/ + $(UPLOADCMD) upload/tmp/$(MAJOR).x/scipy_distutils-{latest,$(SCIPY_DISTUTILS_REV)}.tar.gz $(UPLOADDIR)/$(MAJOR).x +upload/www/$(MAJOR).x/F2PY-$(MAJOR)-latest.win32.exe: upload/tmp/$(MAJOR).x/F2PY-$(MAJOR)-latest.win32.exe + -mkdir -p `dirname $@` + cp -P upload/tmp/$(MAJOR).x/F2PY-{$(MAJOR)-latest,$(REV)}.win32.exe upload/www/$(MAJOR).x + $(UPLOADCMD) upload/tmp/$(MAJOR).x/F2PY-{$(MAJOR)-latest,$(REV)}.win32.exe $(UPLOADDIR)/$(MAJOR).x/ +upload/www/$(MAJOR).x/scipy_distutils-latest.win32.exe: upload/tmp/$(MAJOR).x/scipy_distutils-latest.win32.exe + -mkdir -p `dirname $@` + cp -P upload/tmp/$(MAJOR).x/scipy_distutils-{latest,$(SCIPY_DISTUTILS_REV)}.win32.exe upload/www/$(MAJOR).x + $(UPLOADCMD) upload/tmp/$(MAJOR).x/scipy_distutils-{latest,$(SCIPY_DISTUTILS_REV)}.win32.exe $(UPLOADDIR)/$(MAJOR).x/ + +upload/tmp/usersguide/index.html: docs/usersguide/index.txt $(UG_FILES_DEP:%=upload/www/usersguide/%) + -mkdir -p upload/tmp/usersguide + rest2html $< $@ +upload/tmp/usersguide/f2py_usersguide.tex: docs/usersguide/index.txt $(UG_FILES_DEP:%=upload/www/usersguide/%) + -mkdir -p upload/tmp/usersguide + rest2latex $< $@ +upload/tmp/usersguide/f2py_usersguide.pdf: upload/tmp/usersguide/f2py_usersguide.tex + cd `dirname $@` && pdflatex `basename $<` +upload/tmp/usersguide/%.f: docs/usersguide/%.f + -mkdir -p upload/tmp/usersguide + cp $< $@ +upload/tmp/usersguide/%.f90: docs/usersguide/%.f90 + -mkdir -p upload/tmp/usersguide + cp $< $@ +upload/tmp/usersguide/%.dat: docs/usersguide/%.dat + -mkdir -p upload/tmp/usersguide + cp $< $@ +upload/tmp/usersguide/%.pyf: docs/usersguide/%.pyf + -mkdir -p upload/tmp/usersguide + cp $< $@ +upload/tmp/usersguide/%.py: docs/usersguide/%.py + -mkdir -p upload/tmp/usersguide + cp $< $@ +upload/www/usersguide/%: upload/tmp/usersguide/% + -mkdir -p `dirname $@` + cp -P $< $@ + $(UPLOADCMD) $@ $(UPLOADDIR)/usersguide + +upload/tmp/FAQ.html: docs/FAQ.txt $(FAQ_DEPS:%=docs/%) + -mkdir -p upload/tmp + rest2html $< $@ +upload/tmp/index.html: docs/README.txt $(README_DEPS:%=docs/%) + -mkdir -p upload/tmp + rest2html $< $@ +upload/tmp/%.f: docs/%.f + -mkdir -p upload/tmp + cp $< $@ +upload/tmp/%.html: docs/%.txt + -mkdir -p upload/tmp + rest2html $< $@ +upload/www/%: upload/tmp/% + -mkdir -p `dirname $@` + cp -P $< $@ + $(UPLOADCMD) $@ $(UPLOADDIR)/ + +upload_web: $(WWW_WEB_FILES) +upload_ug: $(WWW_UG_FILES) +upload_src: $(WWW_SRC_FILES) +upload: upload_src upload_ug upload_web + +generate_web: $(TMP_WEB_FILES) +generate: generate_web + +############################################################################## +# Clean up +############################################################################## +clean: + rm -f {tests/,tests/{f77,f90,mixed}/,docs/,docs/usersguide/,}*.{o,a,so,sl,pyc} + rm -f {tests/,tests/{f77,f90,mixed}/,docs/,docs/usersguide/,}*~ +distclean: clean + rm -f {tests/,src/,}*~ + rm -f tests/*.{f,f90} + rm -rf dist {docs/,docs/usersguide/,}build f2py2e scipy_distutils upload + rm -f MANIFEST f2py?.? f2py + +.PHONY: install test diff --git a/numpy/f2py/NEWS.txt b/numpy/f2py/NEWS.txt new file mode 100644 index 000000000..a4a254405 --- /dev/null +++ b/numpy/f2py/NEWS.txt @@ -0,0 +1,2 @@ + +Read docs/HISTORY.txt
\ No newline at end of file diff --git a/numpy/f2py/README.txt b/numpy/f2py/README.txt new file mode 100644 index 000000000..ebe7e8c88 --- /dev/null +++ b/numpy/f2py/README.txt @@ -0,0 +1,5 @@ +====================================================================== + F2PY - Fortran to Python Interface Generator +====================================================================== + +Read docs/README.txt diff --git a/numpy/f2py/TODO.txt b/numpy/f2py/TODO.txt new file mode 100644 index 000000000..fd655f2e2 --- /dev/null +++ b/numpy/f2py/TODO.txt @@ -0,0 +1,67 @@ +Determine fixed/free format Fortran 90 dialect from the +contents of Fortran files. See scipy_distutils/command/build_flib.py. + +[DONE] +======================================================================== +Wrapping F90 code as follows: + +subroutine foo +print*,"In foo" +end subroutine foo +subroutine bar(func) + interface aa ! bug: this interface block is ignored + subroutine foo + end subroutine foo + end interface + !external foo + external func + call func(foo) +end subroutine bar +subroutine gun(a) + external a + call a() +end subroutine gun +subroutine fun + call bar(gun) +end subroutine fun + +========================================================================= +Users Guide needs major revision. + +[DONE] +========================================================================= +On Thu, 27 Sep 2001, José Luis Gómez Dans wrote: + +> Hi, +> just one question: does f2py supporte derived types in F90 code? +> Stuff like something%or and things like that. + +Not yet. + +========================================================================= +Date: Tue, 28 Aug 2001 22:23:04 -0700 +From: Patrick LeGresley <plegresl@ape.stanford.edu> +To: f2py-users@cens.ioc.ee +Subject: [f2py] Strange initialization of allocatable arrays + +I've noticed an odd behavior when setting an allocatable, multidimensional +array in a module. If the rank of the array is odd, the initialization is +fine. However, if the rank is even only the first element of the array is +set properly. See the attached sample code for example. + +========================================================================= +On Wed, 22 Aug 2001, Patrick LeGresley wrote: + +> I've noticed that if a parameter is defined in terms of another parameter, +> that the parameter is replaced not by a number but by another parameter +> (try the attached subroutine for example). Is there any way to have f2py +> automatically recognize the dependencies and generate a signature file +> without parameter variables ? + +It is certainly possible. In fact, f2py has only a basic support for +PARAMETER statements and it fails in your 'advanced' example to produce a +robust signature file. +I am sorry but you have to wait until I'll get back from my travel tour +(somewhere in the middle of September) and get a chance to work on it. + +[DONE] diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py new file mode 100644 index 000000000..5c2c3e927 --- /dev/null +++ b/numpy/f2py/__init__.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +__all__ = ['run_main','compile','f2py_testing'] + +import os +import tempfile +import sys +import commands + +import f2py2e +run_main = f2py2e.run_main +main = f2py2e.main +import f2py_testing + +def compile(source, + modulename = 'untitled', + extra_args = '', + verbose = 1, + source_fn = None + ): + ''' Build extension module from processing source with f2py. + Read the source of this function for more information. + ''' + from scipy.distutils.exec_command import exec_command + if source_fn is None: + fname = os.path.join(tempfile.mktemp()+'.f') + else: + fname = source_fn + + f = open(fname,'w') + f.write(source) + f.close() + + args = ' -c -m %s %s %s'%(modulename,fname,extra_args) + c = '%s -c "import scipy.f2py as f2py2e;f2py2e.main()" %s' %(sys.executable,args) + s,o = exec_command(c) + if source_fn is None: + try: os.remove(fname) + except OSError: pass + return s diff --git a/numpy/f2py/__version__.py b/numpy/f2py/__version__.py new file mode 100644 index 000000000..11fb7b3d2 --- /dev/null +++ b/numpy/f2py/__version__.py @@ -0,0 +1,9 @@ +major = 2 + +try: + from __svn_version__ import version + version_info = (major,version) + version = '%s_%s' % version_info +except Exception,msg: + print msg + version = '%s_?' % (major) diff --git a/numpy/f2py/auxfuncs.py b/numpy/f2py/auxfuncs.py new file mode 100644 index 000000000..51eae0517 --- /dev/null +++ b/numpy/f2py/auxfuncs.py @@ -0,0 +1,489 @@ +#!/usr/bin/env python +""" + +Auxiliary functions for f2py2e. + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/07/24 19:01:55 $ +Pearu Peterson +""" +__version__ = "$Revision: 1.65 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +import pprint +import sys,string,time,types,os +import cfuncs + + +errmess=sys.stderr.write +#outmess=sys.stdout.write +show=pprint.pprint + +options={} +debugoptions=[] +wrapfuncs = 1 + +def outmess(t): + if options.get('verbose',1): + sys.stdout.write(t) + +def debugcapi(var): return 'capi' in debugoptions +def _isstring(var): + return var.has_key('typespec') and var['typespec']=='character' and (not isexternal(var)) +def isstring(var): + return _isstring(var) and not isarray(var) +def ischaracter(var): + return isstring(var) and not (var.has_key('charselector')) +def isstringarray(var): + return isarray(var) and _isstring(var) +def isarrayofstrings(var): + # leaving out '*' for now so that + # `character*(*) a(m)` and `character a(m,*)` + # are treated differently. Luckily `character**` is illegal. + return isstringarray(var) and var['dimension'][-1]=='(*)' +def isarray(var): return var.has_key('dimension') and (not isexternal(var)) +def isscalar(var): return not (isarray(var) or isstring(var) or isexternal(var)) +def iscomplex(var): + return isscalar(var) and var.get('typespec') in ['complex','double complex'] +def islogical(var): + return isscalar(var) and var.get('typespec')=='logical' +def isinteger(var): + return isscalar(var) and var.get('typespec')=='integer' +def isreal(var): + return isscalar(var) and var.get('typespec')=='real' +def get_kind(var): + try: return var['kindselector']['*'] + except KeyError: + try: return var['kindselector']['kind'] + except KeyError: pass +def islong_long(var): + if not isscalar(var): return 0 + if var.get('typespec') not in ['integer','logical']: return 0 + return get_kind(var)=='8' +def isunsigned_char(var): + if not isscalar(var): return 0 + if var.get('typespec') != 'integer': return 0 + return get_kind(var)=='-1' +def isunsigned_short(var): + if not isscalar(var): return 0 + if var.get('typespec') != 'integer': return 0 + return get_kind(var)=='-2' +def isunsigned(var): + if not isscalar(var): return 0 + if var.get('typespec') != 'integer': return 0 + return get_kind(var)=='-4' +def isunsigned_long_long(var): + if not isscalar(var): return 0 + if var.get('typespec') != 'integer': return 0 + return get_kind(var)=='-8' +def isdouble(var): + if not isscalar(var): return 0 + if not var.get('typespec')=='real': return 0 + return get_kind(var)=='8' +def islong_double(var): + if not isscalar(var): return 0 + if not var.get('typespec')=='real': return 0 + return get_kind(var)=='16' +def islong_complex(var): + if not iscomplex(var): return 0 + return get_kind(var)=='32' + +def iscomplexarray(var): return isarray(var) and var.get('typespec') in ['complex','double complex'] +def isint1array(var): return isarray(var) and var.get('typespec')=='integer' \ + and get_kind(var)=='1' +def isunsigned_chararray(var): return isarray(var) and var.get('typespec')=='integer' and get_kind(var)=='-1' +def isunsigned_shortarray(var): return isarray(var) and var.get('typespec')=='integer' and get_kind(var)=='-2' +def isunsignedarray(var): return isarray(var) and var.get('typespec')=='integer' and get_kind(var)=='-4' +def isunsigned_long_longarray(var): return isarray(var) and var.get('typespec')=='integer' and get_kind(var)=='-8' +def isallocatable(var): + return var.has_key('attrspec') and 'allocatable' in var['attrspec'] +def ismutable(var): return not (not var.has_key('dimension') or isstring(var)) +def ismoduleroutine(rout): return rout.has_key('modulename') +def ismodule(rout): return (rout.has_key('block') and 'module'==rout['block']) +def isfunction(rout): return (rout.has_key('block') and 'function'==rout['block']) +#def isfunction_wrap(rout): +# return wrapfuncs and (iscomplexfunction(rout) or isstringfunction(rout)) and (not isexternal(rout)) +def isfunction_wrap(rout): + if isintent_c(rout): return 0 + return wrapfuncs and isfunction(rout) and (not isexternal(rout)) +def issubroutine(rout): return (rout.has_key('block') and 'subroutine'==rout['block']) +def isroutine(rout): return isfunction(rout) or issubroutine(rout) +def islogicalfunction(rout): + if not isfunction(rout): return 0 + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if rout['vars'].has_key(a): return islogical(rout['vars'][a]) + return 0 +def islong_longfunction(rout): + if not isfunction(rout): return 0 + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if rout['vars'].has_key(a): return islong_long(rout['vars'][a]) + return 0 +def islong_doublefunction(rout): + if not isfunction(rout): return 0 + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if rout['vars'].has_key(a): return islong_double(rout['vars'][a]) + return 0 +def iscomplexfunction(rout): + if not isfunction(rout): return 0 + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if rout['vars'].has_key(a): return iscomplex(rout['vars'][a]) + return 0 +def iscomplexfunction_warn(rout): + if iscomplexfunction(rout): + outmess("""\ + ************************************************************** + Warning: code with a function returning complex value + may not work correctly with your Fortran compiler. + Run the following test before using it in your applications: + $(f2py install dir)/test-site/{b/runme_scalar,e/runme} + When using GNU gcc/g77 compilers, codes should work correctly. + **************************************************************\n""") + return 1 + return 0 +def isstringfunction(rout): + if not isfunction(rout): return 0 + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if rout['vars'].has_key(a): return isstring(rout['vars'][a]) + return 0 +def hasexternals(rout): return rout.has_key('externals') and rout['externals'] +def isthreadsafe(rout): return rout.has_key('f2pyenhancements') and rout['f2pyenhancements'].has_key('threadsafe') +def hasvariables(rout): return rout.has_key('vars') and rout['vars'] +def isoptional(var): return (var.has_key('attrspec') and 'optional' in var['attrspec'] and 'required' not in var['attrspec']) and isintent_nothide(var) +def isexternal(var): return (var.has_key('attrspec') and 'external' in var['attrspec']) +def isrequired(var): return not isoptional(var) and isintent_nothide(var) +def isintent_in(var): + if not var.has_key('intent'): return 1 + if 'hide' in var['intent']: return 0 + if 'inplace' in var['intent']: return 0 + if 'in' in var['intent']: return 1 + if 'out' in var['intent']: return 0 + if 'inout' in var['intent']: return 0 + if 'outin' in var['intent']: return 0 + return 1 +def isintent_inout(var): return var.has_key('intent') and ('inout' in var['intent'] or 'outin' in var['intent']) and 'in' not in var['intent'] and 'hide' not in var['intent'] and 'inplace' not in var['intent'] +def isintent_out(var): + return 'out' in var.get('intent',[]) +def isintent_hide(var): return (var.has_key('intent') and ('hide' in var['intent'] or ('out' in var['intent'] and 'in' not in var['intent'] and (not l_or(isintent_inout,isintent_inplace)(var))))) +def isintent_nothide(var): return not isintent_hide(var) +def isintent_c(var): + return 'c' in var.get('intent',[]) +# def isintent_f(var): +# return not isintent_c(var) +def isintent_cache(var): + return 'cache' in var.get('intent',[]) +def isintent_copy(var): + return 'copy' in var.get('intent',[]) +def isintent_overwrite(var): + return 'overwrite' in var.get('intent',[]) +def isintent_callback(var): + return 'callback' in var.get('intent',[]) +def isintent_inplace(var): + return 'inplace' in var.get('intent',[]) +def isintent_aux(var): + return 'aux' in var.get('intent',[]) + +isintent_dict = {isintent_in:'INTENT_IN',isintent_inout:'INTENT_INOUT', + isintent_out:'INTENT_OUT',isintent_hide:'INTENT_HIDE', + isintent_cache:'INTENT_CACHE', + isintent_c:'INTENT_C',isoptional:'OPTIONAL', + isintent_inplace:'INTENT_INPLACE' + } + +def isprivate(var): + return var.has_key('attrspec') and 'private' in var['attrspec'] + +def hasinitvalue(var): return var.has_key('=') +def hasinitvalueasstring(var): + if not hasinitvalue(var): return 0 + return var['='][0] in ['"',"'"] +def hasnote(var): + return var.has_key('note') +def hasresultnote(rout): + if not isfunction(rout): return 0 + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if rout['vars'].has_key(a): return hasnote(rout['vars'][a]) + return 0 +def hascommon(rout): + return rout.has_key('common') +def containscommon(rout): + if hascommon(rout): return 1 + if hasbody(rout): + for b in rout['body']: + if containscommon(b): return 1 + return 0 +def containsmodule(block): + if ismodule(block): return 1 + if not hasbody(block): return 0 + ret = [] + for b in block['body']: + if containsmodule(b): return 1 + return 0 +def hasbody(rout): + return rout.has_key('body') +def hascallstatement(rout): + return getcallstatement(rout) is not None + +def istrue(var): return 1 +def isfalse(var): return 0 + +class F2PYError(Exception): + pass + +class throw_error: + def __init__(self,mess): + self.mess = mess + def __call__(self,var): + mess = '\n\n var = %s\n Message: %s\n' % (var,self.mess) + raise F2PYError,mess + +def l_and(*f): + l,l2='lambda v',[] + for i in range(len(f)): + l='%s,f%d=f[%d]'%(l,i,i) + l2.append('f%d(v)'%(i)) + return eval('%s:%s'%(l,string.join(l2,' and '))) +def l_or(*f): + l,l2='lambda v',[] + for i in range(len(f)): + l='%s,f%d=f[%d]'%(l,i,i) + l2.append('f%d(v)'%(i)) + return eval('%s:%s'%(l,string.join(l2,' or '))) +def l_not(f): + return eval('lambda v,f=f:not f(v)') + +def isdummyroutine(rout): + try: + return rout['f2pyenhancements']['fortranname']=='' + except KeyError: + return 0 + +def getfortranname(rout): + try: + name = rout['f2pyenhancements']['fortranname'] + if name=='': + raise KeyError + if not name: + errmess('Failed to use fortranname from %s\n'%(rout['f2pyenhancements'])) + raise KeyError + except KeyError: + name = rout['name'] + return name + +def getmultilineblock(rout,blockname,comment=1,counter=0): + try: + r = rout['f2pyenhancements'].get(blockname) + except KeyError: + return + if not r: return + if counter>0 and type(r) is type(''): + return + if type(r) is type([]): + if counter>=len(r): return + r = r[counter] + if r[:3]=="'''": + if comment: + r = '\t/* start ' + blockname + ' multiline ('+`counter`+') */\n' + r[3:] + else: + r = r[3:] + if r[-3:]=="'''": + if comment: + r = r[:-3] + '\n\t/* end multiline ('+`counter`+')*/' + else: + r = r[:-3] + else: + errmess("%s multiline block should end with `'''`: %s\n" \ + % (blockname,repr(r))) + return r + +def getcallstatement(rout): + return getmultilineblock(rout,'callstatement') + +def getcallprotoargument(rout,cb_map={}): + r = getmultilineblock(rout,'callprotoargument',comment=0) + if r: return r + if hascallstatement(rout): + outmess('warning: callstatement is defined without callprotoargument\n') + return + from capi_maps import getctype + arg_types,arg_types2 = [],[] + if l_and(isstringfunction,l_not(isfunction_wrap))(rout): + arg_types.extend(['char*','size_t']) + for n in rout['args']: + var = rout['vars'][n] + if isintent_callback(var): + continue + if cb_map.has_key(n): + ctype = cb_map[n]+'_typedef' + else: + ctype = getctype(var) + if l_and(isintent_c,l_or(isscalar,iscomplex))(var): + pass + elif isstring(var): + pass + #ctype = 'void*' + else: + ctype = ctype+'*' + if isstring(var) or isarrayofstrings(var): + arg_types2.append('size_t') + arg_types.append(ctype) + + proto_args = string.join(arg_types+arg_types2,',') + if not proto_args: + proto_args = 'void' + #print proto_args + return proto_args + +def getusercode(rout): + return getmultilineblock(rout,'usercode') +def getusercode1(rout): + return getmultilineblock(rout,'usercode',counter=1) + +def getpymethoddef(rout): + return getmultilineblock(rout,'pymethoddef') + +def getargs(rout): + sortargs,args=[],[] + if rout.has_key('args'): + args=rout['args'] + if rout.has_key('sortvars'): + for a in rout['sortvars']: + if a in args: sortargs.append(a) + for a in args: + if a not in sortargs: + sortargs.append(a) + else: sortargs=rout['args'] + return args,sortargs + +def getargs2(rout): + sortargs,args=[],rout.get('args',[]) + auxvars = [a for a in rout['vars'].keys() if isintent_aux(rout['vars'][a])\ + and a not in args] + args = auxvars + args + if rout.has_key('sortvars'): + for a in rout['sortvars']: + if a in args: sortargs.append(a) + for a in args: + if a not in sortargs: + sortargs.append(a) + else: sortargs=auxvars + rout['args'] + return args,sortargs + +def getrestdoc(rout): + if not rout.has_key('f2pymultilines'): + return None + k = None + if rout['block']=='python module': + k = rout['block'],rout['name'] + return rout['f2pymultilines'].get(k,None) + +def gentitle(name): + l=(80-len(name)-6)/2 + return '/*%s %s %s*/'%(l*'*',name,l*'*') +def flatlist(l): + if type(l)==types.ListType: + return reduce(lambda x,y,f=flatlist:x+f(y),l,[]) + return [l] +def stripcomma(s): + if s and s[-1]==',': return s[:-1] + return s +def replace(str,dict,defaultsep=''): + if type(dict)==types.ListType: + return map(lambda d,f=replace,sep=defaultsep,s=str:f(s,d,sep),dict) + if type(str)==types.ListType: + return map(lambda s,f=replace,sep=defaultsep,d=dict:f(s,d,sep),str) + for k in 2*dict.keys(): + if k=='separatorsfor': continue + if dict.has_key('separatorsfor') and dict['separatorsfor'].has_key(k): + sep=dict['separatorsfor'][k] + else: + sep=defaultsep + if type(dict[k])==types.ListType: + str=string.replace(str,'#%s#'%(k),string.join(flatlist(dict[k]),sep)) + else: + str=string.replace(str,'#%s#'%(k),dict[k]) + return str + +def dictappend(rd,ar): + if type(ar)==types.ListType: + for a in ar: rd=dictappend(rd,a) + return rd + for k in ar.keys(): + if k[0]=='_': continue + if rd.has_key(k): + if type(rd[k])==types.StringType: rd[k]=[rd[k]] + if type(rd[k])==types.ListType: + if type(ar[k])==types.ListType: rd[k]=rd[k]+ar[k] + else: rd[k].append(ar[k]) + elif type(rd[k])==types.DictType: + if type(ar[k])==types.DictType: + if k=='separatorsfor': + for k1 in ar[k].keys(): + if not rd[k].has_key(k1): rd[k][k1]=ar[k][k1] + else: rd[k]=dictappend(rd[k],ar[k]) + else: rd[k]=ar[k] + return rd + +def applyrules(rules,dict,var={}): + ret={} + if type(rules)==types.ListType: + for r in rules: + rr=applyrules(r,dict,var) + ret=dictappend(ret,rr) + if rr.has_key('_break'): break + return ret + if rules.has_key('_check') and (not rules['_check'](var)): return ret + if rules.has_key('need'): + res = applyrules({'needs':rules['need']},dict,var) + if res.has_key('needs'): + cfuncs.append_needs(res['needs']) + + for k in rules.keys(): + if k=='separatorsfor': ret[k]=rules[k]; continue + if type(rules[k])==types.StringType: + ret[k]=replace(rules[k],dict) + elif type(rules[k])==types.ListType: + ret[k]=[] + for i in rules[k]: + ar=applyrules({k:i},dict,var) + if ar.has_key(k): ret[k].append(ar[k]) + elif k[0]=='_': + continue + elif type(rules[k])==types.DictType: + ret[k]=[] + for k1 in rules[k].keys(): + if type(k1)==types.FunctionType and k1(var): + if type(rules[k][k1])==types.ListType: + for i in rules[k][k1]: + if type(i)==types.DictType: + res=applyrules({'supertext':i},dict,var) + if res.has_key('supertext'): i=res['supertext'] + else: i='' + ret[k].append(replace(i,dict)) + else: + i=rules[k][k1] + if type(i)==types.DictType: + res=applyrules({'supertext':i},dict) + if res.has_key('supertext'): i=res['supertext'] + else: i='' + ret[k].append(replace(i,dict)) + else: + errmess('applyrules: ignoring rule %s.\n'%`rules[k]`) + if type(ret[k])==types.ListType: + if len(ret[k])==1: ret[k]=ret[k][0] + if ret[k]==[]: del ret[k] + return ret + + diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py new file mode 100644 index 000000000..e4a542eaa --- /dev/null +++ b/numpy/f2py/capi_maps.py @@ -0,0 +1,723 @@ +#!/usr/bin/env python +""" + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/05/06 10:57:33 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.60 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +import string,copy,re,os +from auxfuncs import * +from crackfortran import markoutercomma +import cb_rules + +# Numarray and Numeric users should set this False +using_newcore = True + +depargs=[] +lcb_map={} +lcb2_map={} +# forced casting: mainly caused by the fact that Python or Numeric +# C/APIs do not support the corresponding C types. +c2py_map={'double':'float', + 'float':'float', # forced casting + 'long_double':'float', # forced casting + 'char':'int', # forced casting + 'signed_char':'int', # forced casting + 'unsigned_char':'int', # forced casting + 'short':'int', # forced casting + 'unsigned_short':'int', # forced casting + 'int':'int', # (forced casting) + 'long':'int', + 'long_long':'long', + 'unsigned':'int', # forced casting + 'complex_float':'complex', # forced casting + 'complex_double':'complex', + 'complex_long_double':'complex', # forced casting + 'string':'string', + } +c2capi_map={'double':'PyArray_DOUBLE', + 'float':'PyArray_FLOAT', + 'long_double':'PyArray_DOUBLE', # forced casting + 'char':'PyArray_CHAR', + 'unsigned_char':'PyArray_UBYTE', + 'signed_char':'PyArray_SBYTE', + 'short':'PyArray_SHORT', + 'unsigned_short':'PyArray_USHORT', + 'int':'PyArray_INT', + 'unsigned':'PyArray_UINT', + 'long':'PyArray_LONG', + 'long_long':'PyArray_LONG', # forced casting + 'complex_float':'PyArray_CFLOAT', + 'complex_double':'PyArray_CDOUBLE', + 'complex_long_double':'PyArray_CDOUBLE', # forced casting + 'string':'PyArray_CHAR'} + +#These new maps aren't used anyhere yet, but should be by default +# unless building numeric or numarray extensions. +if using_newcore: + c2capi_map={'double':'PyArray_DOUBLE', + 'float':'PyArray_FLOAT', + 'long_double':'PyArray_LONGDOUBLE', + 'char':'PyArray_BYTE', + 'unsigned_char':'PyArray_UBYTE', + 'signed_char':'PyArray_BYTE', + 'short':'PyArray_SHORT', + 'unsigned_short':'PyArray_USHORT', + 'int':'PyArray_INT', + 'unsigned':'PyArray_UINT', + 'long':'PyArray_LONG', + 'unsigned_long':'PyArray_ULONG', + 'long_long':'PyArray_LONGLONG', + 'unsigned_long_long':'Pyarray_ULONGLONG', + 'complex_float':'PyArray_CFLOAT', + 'complex_double':'PyArray_CDOUBLE', + 'complex_long_double':'PyArray_CDOUBLE', + 'string':'PyArray_STRING'} +c2pycode_map={'double':'d', + 'float':'f', + 'long_double':'d', # forced casting + 'char':'1', + 'signed_char':'1', + 'unsigned_char':'b', + 'short':'s', + 'unsigned_short':'w', + 'int':'i', + 'unsigned':'u', + 'long':'l', + 'long_long':'L', + 'complex_float':'F', + 'complex_double':'D', + 'complex_long_double':'D', # forced casting + 'string':'c' + } +if using_newcore: + c2pycode_map={'double':'d', + 'float':'f', + 'long_double':'g', + 'char':'b', + 'unsigned_char':'B', + 'signed_char':'b', + 'short':'h', + 'unsigned_short':'H', + 'int':'i', + 'unsigned':'I', + 'long':'l', + 'unsigned_long':'L', + 'long_long':'q', + 'unsigned_long_long':'Q', + 'complex_float':'F', + 'complex_double':'D', + 'complex_long_double':'G', + 'string':'S'} +c2buildvalue_map={'double':'d', + 'float':'f', + 'char':'b', + 'signed_char':'b', + 'short':'h', + 'int':'i', + 'long':'l', + 'long_long':'L', + 'complex_float':'N', + 'complex_double':'N', + 'complex_long_double':'N', + 'string':'z'} +if using_newcore: + #c2buildvalue_map=??? + pass + +f2cmap_all={'real':{'':'float','4':'float','8':'double','12':'long_double','16':'long_double'}, + 'integer':{'':'int','1':'signed_char','2':'short','4':'int','8':'long_long', + '-1':'unsigned_char','-2':'unsigned_short','-4':'unsigned', + '-8':'unsigned_long_long'}, + 'complex':{'':'complex_float','8':'complex_float', + '16':'complex_double','24':'complex_long_double', + '32':'complex_long_double'}, + 'complexkind':{'':'complex_float','4':'complex_float', + '8':'complex_double','12':'complex_long_double', + '16':'complex_long_double'}, + 'logical':{'':'int','1':'char','2':'short','4':'int','8':'long_long'}, + 'double complex':{'':'complex_double'}, + 'double precision':{'':'double'}, + 'byte':{'':'char'}, + 'character':{'':'string'} + } + +if os.path.isfile('.f2py_f2cmap'): + # User defined additions to f2cmap_all. + # .f2py_f2cmap must contain a dictionary of dictionaries, only. + # For example, {'real':{'low':'float'}} means that Fortran 'real(low)' is + # interpreted as C 'float'. + # This feature is useful for F90/95 users if they use PARAMETERSs + # in type specifications. + try: + outmess('Reading .f2py_f2cmap ...\n') + f = open('.f2py_f2cmap','r') + d = eval(f.read(),{},{}) + f.close() + for k,d1 in d.items(): + for k1 in d1.keys(): + d1[string.lower(k1)] = d1[k1] + d[string.lower(k)] = d[k] + for k in d.keys(): + if not f2cmap_all.has_key(k): f2cmap_all[k]={} + for k1 in d[k].keys(): + if c2py_map.has_key(d[k][k1]): + if f2cmap_all[k].has_key(k1): + outmess("\tWarning: redefinition of {'%s':{'%s':'%s'->'%s'}}\n"%(k,k1,f2cmap_all[k][k1],d[k][k1])) + f2cmap_all[k][k1] = d[k][k1] + outmess('\tMapping "%s(kind=%s)" to "%s"\n' % (k,k1,d[k][k1])) + else: + errmess("\tIgnoring map {'%s':{'%s':'%s'}}: '%s' must be in %s\n"%(k,k1,d[k][k1],d[k][k1],c2py_map.keys())) + outmess('Succesfully applied user defined changes from .f2py_f2cmap\n') + except: + errmess('Failed to apply user defined changes from .f2py_f2cmap. Skipping.\n') +cformat_map={'double':'%g', + 'float':'%g', + 'long_double':'%Lg', + 'char':'%d', + 'signed_char':'%d', + 'unsigned_char':'%hhu', + 'short':'%hd', + 'unsigned_short':'%hu', + 'int':'%d', + 'unsigned':'%u', + 'long':'%ld', + 'unsigned_long':'%lu', + 'long_long':'%ld', + 'complex_float':'(%g,%g)', + 'complex_double':'(%g,%g)', + 'complex_long_double':'(%Lg,%Lg)', + 'string':'%s', + } + +############### Auxiliary functions +def getctype(var): + """ + Determines C type + """ + ctype='void' + if isfunction(var): + if var.has_key('result'): a=var['result'] + else: a=var['name'] + if var['vars'].has_key(a): return getctype(var['vars'][a]) + else: errmess('getctype: function %s has no return value?!\n'%a) + elif issubroutine(var): + return ctype + elif var.has_key('typespec') and f2cmap_all.has_key(string.lower(var['typespec'])): + typespec = string.lower(var['typespec']) + f2cmap=f2cmap_all[typespec] + ctype=f2cmap[''] # default type + if var.has_key('kindselector'): + if var['kindselector'].has_key('*'): + try: + ctype=f2cmap[var['kindselector']['*']] + except KeyError: + errmess('getctype: "%s %s %s" not supported.\n'%(var['typespec'],'*',var['kindselector']['*'])) + elif var['kindselector'].has_key('kind'): + if f2cmap_all.has_key(typespec+'kind'): + f2cmap=f2cmap_all[typespec+'kind'] + try: + ctype=f2cmap[var['kindselector']['kind']] + except KeyError: + if f2cmap_all.has_key(typespec): + f2cmap=f2cmap_all[typespec] + try: + ctype=f2cmap[str(var['kindselector']['kind'])] + except KeyError: + errmess('getctype: "%s(kind=%s)" not supported (use .f2py_f2cmap).\n'\ + %(typespec,var['kindselector']['kind'])) + + else: + if not isexternal(var): + errmess('getctype: No C-type found in "%s", assuming void.\n'%var) + return ctype +def getstrlength(var): + if isstringfunction(var): + if var.has_key('result'): a=var['result'] + else: a=var['name'] + if var['vars'].has_key(a): return getstrlength(var['vars'][a]) + else: errmess('getstrlength: function %s has no return value?!\n'%a) + if not isstring(var): + errmess('getstrlength: expected a signature of a string but got: %s\n'%(`var`)) + len='1' + if var.has_key('charselector'): + a=var['charselector'] + if a.has_key('*'): len=a['*'] + elif a.has_key('len'): len=a['len'] + if re.match(r'\(\s*([*]|[:])\s*\)',len) or re.match(r'([*]|[:])',len): + #if len in ['(*)','*','(:)',':']: + if isintent_hide(var): + errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n'%(`var`)) + len='-1' + return len +def getarrdims(a,var,verbose=0): + global depargs + ret={} + if isstring(var) and not isarray(var): + ret['dims']=getstrlength(var) + ret['size']=ret['dims'] + ret['rank']='1' + elif isscalar(var): + ret['size']='1' + ret['rank']='0' + ret['dims']='' + elif isarray(var): +# if not isintent_c(var): +# var['dimension'].reverse() + dim=copy.copy(var['dimension']) + ret['size']=string.join(dim,'*') + try: ret['size']=`eval(ret['size'])` + except: pass + ret['dims']=string.join(dim,',') + ret['rank']=`len(dim)` + ret['rank*[-1]']=`len(dim)*[-1]`[1:-1] + for i in range(len(dim)): # solve dim for dependecies + v=[] + if dim[i] in depargs: v=[dim[i]] + else: + for va in depargs: + if re.match(r'.*?\b%s\b.*'%va,dim[i]): + v.append(va) + for va in v: + if depargs.index(va)>depargs.index(a): + dim[i]='*' + break + ret['setdims'],i='',-1 + for d in dim: + i=i+1 + if d not in ['*',':','(*)','(:)']: + ret['setdims']='%s#varname#_Dims[%d]=%s,'%(ret['setdims'],i,d) + if ret['setdims']: ret['setdims']=ret['setdims'][:-1] + ret['cbsetdims'],i='',-1 + for d in var['dimension']: + i=i+1 + if d not in ['*',':','(*)','(:)']: + ret['cbsetdims']='%s#varname#_Dims[%d]=%s,'%(ret['cbsetdims'],i,d) + elif verbose : + errmess('getarrdims: If in call-back function: array argument %s must have bounded dimensions: got %s\n'%(`a`,`d`)) + if ret['cbsetdims']: ret['cbsetdims']=ret['cbsetdims'][:-1] +# if not isintent_c(var): +# var['dimension'].reverse() + return ret +def getpydocsign(a,var): + global lcb_map + if isfunction(var): + if var.has_key('result'): af=var['result'] + else: af=var['name'] + if var['vars'].has_key(af): return getpydocsign(af,var['vars'][af]) + else: errmess('getctype: function %s has no return value?!\n'%af) + return '','' + sig,sigout=a,a + opt='' + if isintent_in(var): opt='input' + elif isintent_inout(var): opt='in/output' + out_a = a + if isintent_out(var): + for k in var['intent']: + if k[:4]=='out=': + out_a = k[4:] + break + init='' + ctype=getctype(var) + + if hasinitvalue(var): + init,showinit=getinit(a,var) + init='= %s'%(showinit) + if isscalar(var): + if isintent_inout(var): + sig='%s :%s %s rank-0 array(%s,\'%s\')'%(a,init,opt,c2py_map[ctype], + c2pycode_map[ctype],) + else: + sig='%s :%s %s %s'%(a,init,opt,c2py_map[ctype]) + sigout='%s : %s'%(out_a,c2py_map[ctype]) + elif isstring(var): + if isintent_inout(var): + sig='%s :%s %s rank-0 array(string(len=%s),\'c\')'%(a,init,opt,getstrlength(var)) + else: + sig='%s :%s %s string(len=%s)'%(a,init,opt,getstrlength(var)) + sigout='%s : string(len=%s)'%(out_a,getstrlength(var)) + elif isarray(var): + dim=var['dimension'] + rank=`len(dim)` + sig='%s :%s %s rank-%s array(\'%s\') with bounds (%s)'%(a,init,opt,rank, + c2pycode_map[ctype], + string.join(dim,',')) + if a==out_a: + sigout='%s : rank-%s array(\'%s\') with bounds (%s)'\ + %(a,rank,c2pycode_map[ctype],string.join(dim,',')) + else: + sigout='%s : rank-%s array(\'%s\') with bounds (%s) and %s storage'\ + %(out_a,rank,c2pycode_map[ctype],string.join(dim,','),a) + elif isexternal(var): + ua='' + if lcb_map.has_key(a) and lcb2_map.has_key(lcb_map[a]) and lcb2_map[lcb_map[a]].has_key('argname'): + ua=lcb2_map[lcb_map[a]]['argname'] + if not ua==a: ua=' => %s'%ua + else: ua='' + sig='%s : call-back function%s'%(a,ua) + sigout=sig + else: + errmess('getpydocsign: Could not resolve docsignature for "%s".\\n'%a) + return sig,sigout +def getarrdocsign(a,var): + ctype=getctype(var) + if isstring(var) and (not isarray(var)): + sig='%s : rank-0 array(string(len=%s),\'c\')'%(a,getstrlength(var)) + elif isscalar(var): + sig='%s : rank-0 array(%s,\'%s\')'%(a,c2py_map[ctype], + c2pycode_map[ctype],) + elif isarray(var): + dim=var['dimension'] + rank=`len(dim)` + sig='%s : rank-%s array(\'%s\') with bounds (%s)'%(a,rank, + c2pycode_map[ctype], + string.join(dim,',')) + return sig + +def getinit(a,var): + if isstring(var): init,showinit='""',"''" + else: init,showinit='','' + if hasinitvalue(var): + init=var['='] + showinit=init + if iscomplex(var) or iscomplexarray(var): + ret={} + + try: + v = var["="] + if ',' in v: + ret['init.r'],ret['init.i']=string.split(markoutercomma(v[1:-1]),'@,@') + else: + v = eval(v,{},{}) + ret['init.r'],ret['init.i']=str(v.real),str(v.imag) + except: raise 'sign2map: expected complex number `(r,i)\' but got `%s\' as initial value of %s.'%(init,`a`) + if isarray(var): + init='(capi_c.r=%s,capi_c.i=%s,capi_c)'%(ret['init.r'],ret['init.i']) + elif isstring(var): + if not init: init,showinit='""',"''" + if init[0]=="'": + init='"%s"'%(string.replace(init[1:-1],'"','\\"')) + if init[0]=='"': showinit="'%s'"%(init[1:-1]) + return init,showinit + +def sign2map(a,var): + """ + varname,ctype,atype + init,init.r,init.i,pytype + vardebuginfo,vardebugshowvalue,varshowvalue + varrfromat + intent + """ + global lcb_map,cb_map + out_a = a + if isintent_out(var): + for k in var['intent']: + if k[:4]=='out=': + out_a = k[4:] + break + ret={'varname':a,'outvarname':out_a} + ret['ctype']=getctype(var) + intent_flags = [] + for f,s in isintent_dict.items(): + if f(var): intent_flags.append('F2PY_%s'%s) + if intent_flags: + #XXX: Evaluate intent_flags here. + ret['intent'] = string.join(intent_flags,'|') + else: + ret['intent'] = 'F2PY_INTENT_IN' + if isarray(var): ret['varrformat']='N' + elif c2buildvalue_map.has_key(ret['ctype']): + ret['varrformat']=c2buildvalue_map[ret['ctype']] + else: ret['varrformat']='O' + ret['init'],ret['showinit']=getinit(a,var) + if hasinitvalue(var) and iscomplex(var) and not isarray(var): + ret['init.r'],ret['init.i'] = string.split(markoutercomma(ret['init'][1:-1]),'@,@') + if isexternal(var): + ret['cbnamekey']=a + if lcb_map.has_key(a): + ret['cbname']=lcb_map[a] + ret['maxnofargs']=lcb2_map[lcb_map[a]]['maxnofargs'] + ret['nofoptargs']=lcb2_map[lcb_map[a]]['nofoptargs'] + ret['cbdocstr']=lcb2_map[lcb_map[a]]['docstr'] + ret['cblatexdocstr']=lcb2_map[lcb_map[a]]['latexdocstr'] + else: + ret['cbname']=a + errmess('sign2map: Confused: external %s is not in lcb_map%s.\n'%(a,lcb_map.keys())) + if isstring(var): + ret['length']=getstrlength(var) + if isarray(var): + ret=dictappend(ret,getarrdims(a,var)) + dim=copy.copy(var['dimension']) + if c2capi_map.has_key(ret['ctype']): ret['atype']=c2capi_map[ret['ctype']] + # Debug info + if debugcapi(var): + il=[isintent_in,'input',isintent_out,'output', + isintent_inout,'inoutput',isrequired,'required', + isoptional,'optional',isintent_hide,'hidden', + iscomplex,'complex scalar', + l_and(isscalar,l_not(iscomplex)),'scalar', + isstring,'string',isarray,'array', + iscomplexarray,'complex array',isstringarray,'string array', + iscomplexfunction,'complex function', + l_and(isfunction,l_not(iscomplexfunction)),'function', + isexternal,'callback', + isintent_callback,'callback', + isintent_aux,'auxiliary', + #ismutable,'mutable',l_not(ismutable),'immutable', + ] + rl=[] + for i in range(0,len(il),2): + if il[i](var): rl.append(il[i+1]) + if isstring(var): + rl.append('slen(%s)=%s'%(a,ret['length'])) + if isarray(var): +# if not isintent_c(var): +# var['dimension'].reverse() + ddim=string.join(map(lambda x,y:'%s|%s'%(x,y),var['dimension'],dim),',') + rl.append('dims(%s)'%ddim) +# if not isintent_c(var): +# var['dimension'].reverse() + if isexternal(var): + ret['vardebuginfo']='debug-capi:%s=>%s:%s'%(a,ret['cbname'],string.join(rl,',')) + else: + ret['vardebuginfo']='debug-capi:%s %s=%s:%s'%(ret['ctype'],a,ret['showinit'],string.join(rl,',')) + if isscalar(var): + if cformat_map.has_key(ret['ctype']): + ret['vardebugshowvalue']='debug-capi:%s=%s'%(a,cformat_map[ret['ctype']]) + if isstring(var): + ret['vardebugshowvalue']='debug-capi:slen(%s)=%%d %s=\\"%%s\\"'%(a,a) + if isexternal(var): + ret['vardebugshowvalue']='debug-capi:%s=%%p'%(a) + if cformat_map.has_key(ret['ctype']): + ret['varshowvalue']='#name#:%s=%s'%(a,cformat_map[ret['ctype']]) + ret['showvalueformat']='%s'%(cformat_map[ret['ctype']]) + if isstring(var): + ret['varshowvalue']='#name#:slen(%s)=%%d %s=\\"%%s\\"'%(a,a) + ret['pydocsign'],ret['pydocsignout']=getpydocsign(a,var) + if hasnote(var): + ret['note']=var['note'] + return ret + +def routsign2map(rout): + """ + name,NAME,begintitle,endtitle + rname,ctype,rformat + routdebugshowvalue + """ + global lcb_map + name = rout['name'] + fname = getfortranname(rout) + ret={'name':name, + 'texname':string.replace(name,'_','\\_'), + 'name_lower':string.lower(name), + 'NAME':string.upper(name), + 'begintitle':gentitle(name), + 'endtitle':gentitle('end of %s'%name), + 'fortranname':fname, + 'FORTRANNAME':string.upper(fname), + 'callstatement':getcallstatement(rout) or '', + 'usercode':getusercode(rout) or '', + 'usercode1':getusercode1(rout) or '', + } + if '_' in fname: + ret['F_FUNC'] = 'F_FUNC_US' + else: + ret['F_FUNC'] = 'F_FUNC' + if '_' in name: + ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC_US' + else: + ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC' + lcb_map={} + if rout.has_key('use'): + for u in rout['use'].keys(): + if cb_rules.cb_map.has_key(u): + for un in cb_rules.cb_map[u]: + ln=un[0] + if rout['use'][u].has_key('map'): + for k in rout['use'][u]['map'].keys(): + if rout['use'][u]['map'][k]==un[0]: ln=k;break + lcb_map[ln]=un[1] + #else: + # errmess('routsign2map: cb_map does not contain module "%s" used in "use" statement.\n'%(u)) + elif rout.has_key('externals') and rout['externals']: + errmess('routsign2map: Confused: function %s has externals %s but no "use" statement.\n'%(ret['name'],`rout['externals']`)) + ret['callprotoargument'] = getcallprotoargument(rout,lcb_map) or '' + if isfunction(rout): + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + ret['rname']=a + ret['pydocsign'],ret['pydocsignout']=getpydocsign(a,rout) + ret['ctype']=getctype(rout['vars'][a]) + if hasresultnote(rout): + ret['resultnote']=rout['vars'][a]['note'] + rout['vars'][a]['note']=['See elsewhere.'] + if c2buildvalue_map.has_key(ret['ctype']): + ret['rformat']=c2buildvalue_map[ret['ctype']] + else: + ret['rformat']='O' + errmess('routsign2map: no c2buildvalue key for type %s\n'%(`ret['ctype']`)) + if debugcapi(rout): + if cformat_map.has_key(ret['ctype']): + ret['routdebugshowvalue']='debug-capi:%s=%s'%(a,cformat_map[ret['ctype']]) + if isstringfunction(rout): + ret['routdebugshowvalue']='debug-capi:slen(%s)=%%d %s=\\"%%s\\"'%(a,a) + if isstringfunction(rout): + ret['rlength']=getstrlength(rout['vars'][a]) + if ret['rlength']=='-1': + errmess('routsign2map: expected explicit specification of the length of the string returned by the fortran function %s; taking 10.\n'%(`rout['name']`)) + ret['rlength']='10' + if hasnote(rout): + ret['note']=rout['note'] + rout['note']=['See elsewhere.'] + return ret + +def modsign2map(m): + """ + modulename + """ + if ismodule(m): + ret={'f90modulename':m['name'], + 'F90MODULENAME':string.upper(m['name']), + 'texf90modulename':string.replace(m['name'],'_','\\_')} + else: + ret={'modulename':m['name'], + 'MODULENAME':string.upper(m['name']), + 'texmodulename':string.replace(m['name'],'_','\\_')} + ret['restdoc'] = getrestdoc(m) or [] + if hasnote(m): + ret['note']=m['note'] + #m['note']=['See elsewhere.'] + ret['usercode'] = getusercode(m) or '' + ret['usercode1'] = getusercode1(m) or '' + if m['body']: + ret['interface_usercode'] = getusercode(m['body'][0]) or '' + else: + ret['interface_usercode'] = '' + ret['pymethoddef'] = getpymethoddef(m) or '' + return ret + +def cb_sign2map(a,var): + ret={'varname':a} + ret['ctype']=getctype(var) + if c2capi_map.has_key(ret['ctype']): + ret['atype']=c2capi_map[ret['ctype']] + if cformat_map.has_key(ret['ctype']): + ret['showvalueformat']='%s'%(cformat_map[ret['ctype']]) + if isarray(var): + ret=dictappend(ret,getarrdims(a,var)) + ret['pydocsign'],ret['pydocsignout']=getpydocsign(a,var) + if hasnote(var): + ret['note']=var['note'] + var['note']=['See elsewhere.'] + return ret + +def cb_routsign2map(rout,um): + """ + name,begintitle,endtitle,argname + ctype,rctype,maxnofargs,nofoptargs,returncptr + """ + ret={'name':'cb_%s_in_%s'%(rout['name'],um), + 'returncptr':''} + if isintent_callback(rout): + if '_' in rout['name']: + F_FUNC='F_FUNC_US' + else: + F_FUNC='F_FUNC' + ret['callbackname'] = '%s(%s,%s)' \ + % (F_FUNC, + rout['name'].lower(), + rout['name'].upper(), + ) + ret['static'] = 'extern' + else: + ret['callbackname'] = ret['name'] + ret['static'] = 'static' + ret['argname']=rout['name'] + ret['begintitle']=gentitle(ret['name']) + ret['endtitle']=gentitle('end of %s'%ret['name']) + ret['ctype']=getctype(rout) + ret['rctype']='void' + if ret['ctype']=='string': ret['rctype']='void' + else: + ret['rctype']=ret['ctype'] + if ret['rctype']!='void': + if iscomplexfunction(rout): + ret['returncptr'] = """ +#ifdef F2PY_CB_RETURNCOMPLEX +return_value= +#endif +""" + else: + ret['returncptr'] = 'return_value=' + if cformat_map.has_key(ret['ctype']): + ret['showvalueformat']='%s'%(cformat_map[ret['ctype']]) + if isstringfunction(rout): + ret['strlength']=getstrlength(rout) + if isfunction(rout): + if rout.has_key('result'): a=rout['result'] + else: a=rout['name'] + if hasnote(rout['vars'][a]): + ret['note']=rout['vars'][a]['note'] + rout['vars'][a]['note']=['See elsewhere.'] + ret['rname']=a + ret['pydocsign'],ret['pydocsignout']=getpydocsign(a,rout) + if iscomplexfunction(rout): + ret['rctype']=""" +#ifdef F2PY_CB_RETURNCOMPLEX +#ctype# +#else +void +#endif +""" + else: + if hasnote(rout): + ret['note']=rout['note'] + rout['note']=['See elsewhere.'] + nofargs=0 + nofoptargs=0 + if rout.has_key('args') and rout.has_key('vars'): + for a in rout['args']: + var=rout['vars'][a] + if l_or(isintent_in,isintent_inout)(var): + nofargs=nofargs+1 + if isoptional(var): + nofoptargs=nofoptargs+1 + ret['maxnofargs']=`nofargs` + ret['nofoptargs']=`nofoptargs` + if hasnote(rout) and isfunction(rout) and rout.has_key('result'): + ret['routnote']=rout['note'] + rout['note']=['See elsewhere.'] + return ret + +def common_sign2map(a,var): # obsolute + ret={'varname':a} + ret['ctype']=getctype(var) + if isstringarray(var): ret['ctype']='char' + if c2capi_map.has_key(ret['ctype']): + ret['atype']=c2capi_map[ret['ctype']] + if cformat_map.has_key(ret['ctype']): + ret['showvalueformat']='%s'%(cformat_map[ret['ctype']]) + if isarray(var): + ret=dictappend(ret,getarrdims(a,var)) + elif isstring(var): + ret['size']=getstrlength(var) + ret['rank']='1' + ret['pydocsign'],ret['pydocsignout']=getpydocsign(a,var) + if hasnote(var): + ret['note']=var['note'] + var['note']=['See elsewhere.'] + ret['arrdocstr']=getarrdocsign(a,var) # for strings this returns 0-rank but actually is 1-rank + return ret + + diff --git a/numpy/f2py/cb_rules.py b/numpy/f2py/cb_rules.py new file mode 100644 index 000000000..666c1c6c8 --- /dev/null +++ b/numpy/f2py/cb_rules.py @@ -0,0 +1,534 @@ +#!/usr/bin/env python +""" + +Build call-back mechanism for f2py2e. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/07/20 11:27:58 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.53 $"[10:-1] + +import __version__ +f2py_version = __version__.version + + +import pprint +import sys,string,time,types,copy +errmess=sys.stderr.write +outmess=sys.stdout.write +show=pprint.pprint + +from auxfuncs import * +import capi_maps +#from capi_maps import * +import cfuncs + +################## Rules for callback function ############## + +cb_routine_rules={ + 'cbtypedefs':'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);', + 'body':""" +#begintitle# +PyObject *#name#_capi = NULL;/*was Py_None*/ +PyTupleObject *#name#_args_capi = NULL; +int #name#_nofargs = 0; +jmp_buf #name#_jmpbuf; +/*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/ +#static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) { +\tPyTupleObject *capi_arglist = #name#_args_capi; +\tPyObject *capi_return = NULL; +\tPyObject *capi_tmp = NULL; +\tint capi_j,capi_i = 0; +\tint capi_longjmp_ok = 1; +#decl# +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_start_clock(); +#endif +\tCFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\"); +\tCFUNCSMESSPY(\"cb:#name#_capi=\",#name#_capi); +\tif (#name#_capi==NULL) { +\t\tcapi_longjmp_ok = 0; +\t\t#name#_capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\"); +\t} +\tif (#name#_capi==NULL) { +\t\tPyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\"); +\t\tgoto capi_fail; +\t} +\tif (PyCObject_Check(#name#_capi)) { +\t#name#_typedef #name#_cptr; +\t#name#_cptr = PyCObject_AsVoidPtr(#name#_capi); +\t#returncptr#(*#name#_cptr)(#optargs_nm##args_nm#); +\t#return# +\t} +\tif (capi_arglist==NULL) { +\t\tcapi_longjmp_ok = 0; +\t\tcapi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\"); +\t\tif (capi_tmp) { +\t\t\tcapi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp); +\t\t\tif (capi_arglist==NULL) { +\t\t\t\tPyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\"); +\t\t\t\tgoto capi_fail; +\t\t\t} +\t\t} else { +\t\t\tPyErr_Clear(); +\t\t\tcapi_arglist = (PyTupleObject *)Py_BuildValue(\"()\"); +\t\t} +\t} +\tif (capi_arglist == NULL) { +\t\tPyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\"); +\t\tgoto capi_fail; +\t} +#setdims# +#pyobjfrom# +\tCFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist); +\tCFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\"); +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_start_call_clock(); +#endif +\tcapi_return = PyObject_CallObject(#name#_capi,(PyObject *)capi_arglist); +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_stop_call_clock(); +#endif +\tCFUNCSMESSPY(\"cb:capi_return=\",capi_return); +\tif (capi_return == NULL) { +\t\tfprintf(stderr,\"capi_return is NULL\\n\"); +\t\tgoto capi_fail; +\t} +\tif (capi_return == Py_None) { +\t\tPy_DECREF(capi_return); +\t\tcapi_return = Py_BuildValue(\"()\"); +\t} +\telse if (!PyTuple_Check(capi_return)) { +\t\tcapi_return = Py_BuildValue(\"(N)\",capi_return); +\t} +\tcapi_j = PyTuple_Size(capi_return); +\tcapi_i = 0; +#frompyobj# +\tCFUNCSMESS(\"cb:#name#:successful\\n\"); +\tPy_DECREF(capi_return); +#ifdef F2PY_REPORT_ATEXIT +f2py_cb_stop_clock(); +#endif +\tgoto capi_return_pt; +capi_fail: +\tfprintf(stderr,\"Call-back #name# failed.\\n\"); +\tPy_XDECREF(capi_return); +\tif (capi_longjmp_ok) +\t\tlongjmp(#name#_jmpbuf,-1); +capi_return_pt: +\t; +#return# +} +#endtitle# +""", + 'need':['setjmp.h','CFUNCSMESS'], + 'maxnofargs':'#maxnofargs#', + 'nofoptargs':'#nofoptargs#', + 'docstr':"""\ +\tdef #argname#(#docsignature#): return #docreturn#\\n\\ +#docstrsigns#""", + 'latexdocstr':""" +{{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}} +#routnote# + +#latexdocstrsigns#""", + 'docstrshort':'def #argname#(#docsignature#): return #docreturn#' + } +cb_rout_rules=[ + {# Init + 'separatorsfor':{'decl':'\n', + 'args':',','optargs':'','pyobjfrom':'\n','freemem':'\n', + 'args_td':',','optargs_td':'', + 'args_nm':',','optargs_nm':'', + 'frompyobj':'\n','setdims':'\n', + 'docstrsigns':'\\n"\n"', + 'latexdocstrsigns':'\n', + 'latexdocstrreq':'\n','latexdocstropt':'\n', + 'latexdocstrout':'\n','latexdocstrcbs':'\n', + }, + 'decl':'/*decl*/','pyobjfrom':'/*pyobjfrom*/','frompyobj':'/*frompyobj*/', + 'args':[],'optargs':'','return':'','strarglens':'','freemem':'/*freemem*/', + 'args_td':[],'optargs_td':'','strarglens_td':'', + 'args_nm':[],'optargs_nm':'','strarglens_nm':'', + 'noargs':'', + 'setdims':'/*setdims*/', + 'docstrsigns':'','latexdocstrsigns':'', + 'docstrreq':'\tRequired arguments:', + 'docstropt':'\tOptional arguments:', + 'docstrout':'\tReturn objects:', + 'docstrcbs':'\tCall-back functions:', + 'docreturn':'','docsign':'','docsignopt':'', + 'latexdocstrreq':'\\noindent Required arguments:', + 'latexdocstropt':'\\noindent Optional arguments:', + 'latexdocstrout':'\\noindent Return objects:', + 'latexdocstrcbs':'\\noindent Call-back functions:', + 'routnote':{hasnote:'--- #note#',l_not(hasnote):''}, + },{ # Function + 'decl':'\t#ctype# return_value;', + 'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting return_value->");'}, + '\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n");', + {debugcapi:'\tfprintf(stderr,"#showvalueformat#.\\n",return_value);'} + ], + 'need':['#ctype#_from_pyobj',{debugcapi:'CFUNCSMESS'},'GETSCALARFROMPYTUPLE'], + 'return':'\treturn return_value;', + '_check':l_and(isfunction,l_not(isstringfunction),l_not(iscomplexfunction)) + }, + {# String function + 'pyobjfrom':{debugcapi:'\tfprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'}, + 'args':'#ctype# return_value,int return_value_len', + 'args_nm':'return_value,&return_value_len', + 'args_td':'#ctype# ,int', + 'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting return_value->\\"");'}, + """\tif (capi_j>capi_i) +\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);""", + {debugcapi:'\tfprintf(stderr,"#showvalueformat#\\".\\n",return_value);'} + ], + 'need':['#ctype#_from_pyobj',{debugcapi:'CFUNCSMESS'}, + 'string.h','GETSTRFROMPYTUPLE'], + 'return':'return;', + '_check':isstringfunction + }, + {# Complex function + 'optargs':""" +#ifndef F2PY_CB_RETURNCOMPLEX +#ctype# *return_value +#endif +""", + 'optargs_nm':""" +#ifndef F2PY_CB_RETURNCOMPLEX +return_value +#endif +""", + 'optargs_td':""" +#ifndef F2PY_CB_RETURNCOMPLEX +#ctype# * +#endif +""", + 'decl':""" +#ifdef F2PY_CB_RETURNCOMPLEX +\t#ctype# return_value; +#endif +""", + 'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting return_value->");'}, + """\ +\tif (capi_j>capi_i) +#ifdef F2PY_CB_RETURNCOMPLEX +\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\"); +#else +\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\"); +#endif +""", + {debugcapi:""" +#ifdef F2PY_CB_RETURNCOMPLEX +\tfprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i); +#else +\tfprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i); +#endif + +"""} + ], + 'return':""" +#ifdef F2PY_CB_RETURNCOMPLEX +\treturn return_value; +#else +\treturn; +#endif +""", + 'need':['#ctype#_from_pyobj',{debugcapi:'CFUNCSMESS'}, + 'string.h','GETSCALARFROMPYTUPLE','#ctype#'], + '_check':iscomplexfunction + }, + {'docstrout':'\t\t#pydocsignout#', + 'latexdocstrout':['\\item[]{{}\\verb@#pydocsignout#@{}}', + {hasnote:'--- #note#'}], + 'docreturn':'#rname#,', + '_check':isfunction}, + {'_check':issubroutine,'return':'return;'} + ] + +cb_arg_rules=[ + { # Doc + 'docstropt':{l_and(isoptional,isintent_nothide):'\t\t#pydocsign#'}, + 'docstrreq':{l_and(isrequired,isintent_nothide):'\t\t#pydocsign#'}, + 'docstrout':{isintent_out:'\t\t#pydocsignout#'}, + 'latexdocstropt':{l_and(isoptional,isintent_nothide):['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote:'--- #note#'}]}, + 'latexdocstrreq':{l_and(isrequired,isintent_nothide):['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote:'--- #note#'}]}, + 'latexdocstrout':{isintent_out:['\\item[]{{}\\verb@#pydocsignout#@{}}', + {l_and(hasnote,isintent_hide):'--- #note#', + l_and(hasnote,isintent_nothide):'--- See above.'}]}, + 'docsign':{l_and(isrequired,isintent_nothide):'#varname#,'}, + 'docsignopt':{l_and(isoptional,isintent_nothide):'#varname#,'}, + 'depend':'' + }, + { + 'args':{ + l_and (isscalar,isintent_c):'#ctype# #varname#', + l_and (isscalar,l_not(isintent_c)):'#ctype# *#varname#_cb_capi', + isarray:'#ctype# *#varname#', + isstring:'#ctype# #varname#' + }, + 'args_nm':{ + l_and (isscalar,isintent_c):'#varname#', + l_and (isscalar,l_not(isintent_c)):'#varname#_cb_capi', + isarray:'#varname#', + isstring:'#varname#' + }, + 'args_td':{ + l_and (isscalar,isintent_c):'#ctype#', + l_and (isscalar,l_not(isintent_c)):'#ctype# *', + isarray:'#ctype# *', + isstring:'#ctype#' + }, + 'strarglens':{isstring:',int #varname#_cb_len'}, # untested with multiple args + 'strarglens_td':{isstring:',int'}, # untested with multiple args + + }, + { # Scalars + 'decl':{l_not(isintent_c):'\t#ctype# #varname#=(*#varname#_cb_capi);'}, + 'error': {l_and(isintent_c,isintent_out, + throw_error('intent(c,out) is forbidden for callback scalar arguments')):\ + ''}, + 'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting #varname#->");'}, + {isintent_out:'\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'}, + {l_and(debugcapi,l_and(l_not(iscomplex),isintent_c)):'\tfprintf(stderr,"#showvalueformat#.\\n",#varname#);'}, + {l_and(debugcapi,l_and(l_not(iscomplex),l_not(isintent_c))):'\tfprintf(stderr,"#showvalueformat#.\\n",*#varname#_cb_capi);'}, + {l_and(debugcapi,l_and(iscomplex,isintent_c)):'\tfprintf(stderr,"#showvalueformat#.\\n",(#varname#).r,(#varname#).i);'}, + {l_and(debugcapi,l_and(iscomplex,l_not(isintent_c))):'\tfprintf(stderr,"#showvalueformat#.\\n",(*#varname#_cb_capi).r,(*#varname#_cb_capi).i);'}, + ], + 'need':[{isintent_out:['#ctype#_from_pyobj','GETSCALARFROMPYTUPLE']}, + {debugcapi:'CFUNCSMESS'}], + '_check':isscalar + },{ + 'pyobjfrom':[{isintent_in:"""\ +\tif (#name#_nofargs>capi_i) +\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyobj_from_#ctype#1(#varname#))) +\t\t\tgoto capi_fail;"""}, + {isintent_inout:"""\ +\tif (#name#_nofargs>capi_i) +\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyarr_from_p_#ctype#1(#varname#_cb_capi))) +\t\t\tgoto capi_fail;"""}], + 'need':[{isintent_in:'pyobj_from_#ctype#1'}, + {isintent_inout:'pyarr_from_p_#ctype#1'}, + {iscomplex:'#ctype#'}], + '_check':l_and(isscalar,isintent_nothide), + '_optional':'' + },{# String + 'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting #varname#->\\"");'}, + """\tif (capi_j>capi_i) +\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,#varname#,#varname#_cb_len);""", + {debugcapi:'\tfprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname#,#varname#_cb_len);'}, + ], + 'need':['#ctype#','GETSTRFROMPYTUPLE', + {debugcapi:'CFUNCSMESS'},'string.h'], + '_check':l_and(isstring,isintent_out) + },{ + 'pyobjfrom':[{debugcapi:'\tfprintf(stderr,"debug-capi:cb:#varname#=\\"#showvalueformat#\\":%d:\\n",#varname#,#varname#_cb_len);'}, + {isintent_in:"""\ +\tif (#name#_nofargs>capi_i) +\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyobj_from_#ctype#1(#varname#))) +\t\t\tgoto capi_fail;"""}, + {isintent_inout:"""\ +\tif (#name#_nofargs>capi_i) { +\t\tint #varname#_cb_dims[] = {#varname#_cb_len}; +\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyarr_from_p_#ctype#1(#varname#,#varname#_cb_dims))) +\t\t\tgoto capi_fail; +\t}"""}], + 'need':[{isintent_in:'pyobj_from_#ctype#1'}, + {isintent_inout:'pyarr_from_p_#ctype#1'}], + '_check':l_and(isstring,isintent_nothide), + '_optional':'' + }, +# Array ... + { + 'decl':'\tintp #varname#_Dims[#rank#] = {#rank*[-1]#};', + 'setdims':'\t#cbsetdims#;', + '_check':isarray, + '_depend':'' + }, + { + 'pyobjfrom':[{debugcapi:'\tfprintf(stderr,"debug-capi:cb:#varname#\\n");'}, + {isintent_c:"""\ +\tif (#name#_nofargs>capi_i) { +\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname#_Dims,#atype#,NULL,(char*)#varname#,0,CARRAY_FLAGS,NULL); /*XXX: Hmm, what will destroy this array??? */ +""", + l_not(isintent_c):"""\ +\tif (#name#_nofargs>capi_i) { +\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname#_Dims,#atype#,NULL,(char*)#varname#,0,FARRAY_FLAGS,NULL); /*XXX: Hmm, what will destroy this array??? */ +""", + }, + """ +\t\tif (tmp_arr==NULL) +\t\t\tgoto capi_fail; +\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,(PyObject *)tmp_arr)) +\t\t\tgoto capi_fail; +}"""], + '_check':l_and(isarray,isintent_nothide,l_or(isintent_in,isintent_inout)), + '_optional':'', + },{ + 'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting #varname#->");'}, + """\tif (capi_j>capi_i) { +\t\tPyArrayObject *rv_cb_arr = NULL; +\t\tif ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail; +\t\trv_cb_arr = array_from_pyobj(#atype#,#varname#_Dims,#rank#,F2PY_INTENT_IN""", + {isintent_c:'|F2PY_INTENT_C'}, + """,capi_tmp); +\t\tif (rv_cb_arr == NULL) { +\t\t\tfprintf(stderr,\"rv_cb_arr is NULL\\n\"); +\t\t\tgoto capi_fail; +\t\t} +\t\tMEMCOPY(#varname#,rv_cb_arr->data,PyArray_NBYTES(rv_cb_arr)); +\t\tif (capi_tmp != (PyObject *)rv_cb_arr) { +\t\t\tPy_DECREF(rv_cb_arr); +\t\t} +\t}""", + {debugcapi:'\tfprintf(stderr,"<-.\\n");'}, + ], + 'need':['MEMCOPY',{iscomplexarray:'#ctype#'}], + '_check':l_and(isarray,isintent_out) + },{ + 'docreturn':'#varname#,', + '_check':isintent_out + } + ] + +################## Build call-back module ############# +cb_map={} +def buildcallbacks(m): + global cb_map + cb_map[m['name']]=[] + for bi in m['body']: + if bi['block']=='interface': + for b in bi['body']: + if b: + buildcallback(b,m['name']) + else: + errmess('warning: empty body for %s\n' % (m['name'])) + +def buildcallback(rout,um): + global cb_map + outmess('\tConstructing call-back function "cb_%s_in_%s"\n'%(rout['name'],um)) + args,depargs=getargs(rout) + capi_maps.depargs=depargs + var=rout['vars'] + vrd=capi_maps.cb_routsign2map(rout,um) + rd=dictappend({},vrd) + cb_map[um].append([rout['name'],rd['name']]) + for r in cb_rout_rules: + if (r.has_key('_check') and r['_check'](rout)) or (not r.has_key('_check')): + ar=applyrules(r,vrd,rout) + rd=dictappend(rd,ar) + savevrd={} + for a in args: + vrd=capi_maps.cb_sign2map(a,var[a]) + savevrd[a]=vrd + for r in cb_arg_rules: + if r.has_key('_depend'): continue + if r.has_key('_optional') and isoptional(var[a]): continue + if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')): + ar=applyrules(r,vrd,var[a]) + rd=dictappend(rd,ar) + if r.has_key('_break'): break + for a in args: + vrd=savevrd[a] + for r in cb_arg_rules: + if r.has_key('_depend'): continue + if (not r.has_key('_optional')) or (r.has_key('_optional') and isrequired(var[a])): continue + if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')): + ar=applyrules(r,vrd,var[a]) + rd=dictappend(rd,ar) + if r.has_key('_break'): break + for a in depargs: + vrd=savevrd[a] + for r in cb_arg_rules: + if not r.has_key('_depend'): continue + if r.has_key('_optional'): continue + if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')): + ar=applyrules(r,vrd,var[a]) + rd=dictappend(rd,ar) + if r.has_key('_break'): break + if rd.has_key('args') and rd.has_key('optargs'): + if type(rd['optargs'])==type([]): + rd['optargs']=rd['optargs']+[""" +#ifndef F2PY_CB_RETURNCOMPLEX +, +#endif +"""] + rd['optargs_nm']=rd['optargs_nm']+[""" +#ifndef F2PY_CB_RETURNCOMPLEX +, +#endif +"""] + rd['optargs_td']=rd['optargs_td']+[""" +#ifndef F2PY_CB_RETURNCOMPLEX +, +#endif +"""] + if type(rd['docreturn'])==types.ListType: + rd['docreturn']=stripcomma(replace('#docreturn#',{'docreturn':rd['docreturn']})) + optargs=stripcomma(replace('#docsignopt#', + {'docsignopt':rd['docsignopt']} + )) + if optargs=='': + rd['docsignature']=stripcomma(replace('#docsign#',{'docsign':rd['docsign']})) + else: + rd['docsignature']=replace('#docsign#[#docsignopt#]', + {'docsign':rd['docsign'], + 'docsignopt':optargs, + }) + rd['latexdocsignature']=string.replace(rd['docsignature'],'_','\\_') + rd['latexdocsignature']=string.replace(rd['latexdocsignature'],',',', ') + rd['docstrsigns']=[] + rd['latexdocstrsigns']=[] + for k in ['docstrreq','docstropt','docstrout','docstrcbs']: + if rd.has_key(k) and type(rd[k])==types.ListType: + rd['docstrsigns']=rd['docstrsigns']+rd[k] + k='latex'+k + if rd.has_key(k) and type(rd[k])==types.ListType: + rd['latexdocstrsigns']=rd['latexdocstrsigns']+rd[k][0:1]+\ + ['\\begin{description}']+rd[k][1:]+\ + ['\\end{description}'] + if not rd.has_key('args'): + rd['args']='' + rd['args_td']='' + rd['args_nm']='' + if not (rd.get('args') or rd.get('optargs') or rd.get('strarglens')): + rd['noargs'] = 'void' + + ar=applyrules(cb_routine_rules,rd) + cfuncs.callbacks[rd['name']]=ar['body'] + if type(ar['need'])==types.StringType: + ar['need']=[ar['need']] + + if rd.has_key('need'): + for t in cfuncs.typedefs.keys(): + if t in rd['need']: + ar['need'].append(t) + + cfuncs.typedefs_generated[rd['name']+'_typedef'] = ar['cbtypedefs'] + ar['need'].append(rd['name']+'_typedef') + cfuncs.needs[rd['name']]=ar['need'] + + capi_maps.lcb2_map[rd['name']]={'maxnofargs':ar['maxnofargs'], + 'nofoptargs':ar['nofoptargs'], + 'docstr':ar['docstr'], + 'latexdocstr':ar['latexdocstr'], + 'argname':rd['argname'] + } + outmess('\t %s\n'%(ar['docstrshort'])) + #print ar['body'] + return +################## Build call-back function ############# + + + + + diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py new file mode 100644 index 000000000..aec1509ff --- /dev/null +++ b/numpy/f2py/cfuncs.py @@ -0,0 +1,1134 @@ +#!/usr/bin/env python +""" + +C declarations, CPP macros, and C functions for f2py2e. +Only required declarations/macros/functions will be used. + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/05/06 11:42:34 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.75 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +import types,sys,copy,os +errmess=sys.stderr.write + +##################### Definitions ################## + +outneeds={'includes0':[],'includes':[],'typedefs':[],'typedefs_generated':[], + 'userincludes':[], + 'cppmacros':[],'cfuncs':[],'callbacks':[],'f90modhooks':[], + 'commonhooks':[]} +needs={} +includes0={'includes0':'/*need_includes0*/'} +includes={'includes':'/*need_includes*/'} +userincludes={'userincludes':'/*need_userincludes*/'} +typedefs={'typedefs':'/*need_typedefs*/'} +typedefs_generated={'typedefs_generated':'/*need_typedefs_generated*/'} +cppmacros={'cppmacros':'/*need_cppmacros*/'} +cfuncs={'cfuncs':'/*need_cfuncs*/'} +callbacks={'callbacks':'/*need_callbacks*/'} +f90modhooks={'f90modhooks':'/*need_f90modhooks*/', + 'initf90modhooksstatic':'/*initf90modhooksstatic*/', + 'initf90modhooksdynamic':'/*initf90modhooksdynamic*/', + } +commonhooks={'commonhooks':'/*need_commonhooks*/', + 'initcommonhooks':'/*need_initcommonhooks*/', + } + +############ Includes ################### + +includes0['math.h']='#include <math.h>' +includes0['string.h']='#include <string.h>' +includes0['setjmp.h']='#include <setjmp.h>' + +includes['Python.h']='#include "Python.h"' +needs['arrayobject.h']=['Python.h'] +includes['arrayobject.h']='''#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API +#include "arrayobject.h"''' + +includes['arrayobject.h']='#include "fortranobject.h"' + +############# Type definitions ############### + +typedefs['unsigned_char']='typedef unsigned char unsigned_char;' +typedefs['unsigned_short']='typedef unsigned short unsigned_short;' +typedefs['unsigned_long']='typedef unsigned long unsigned_long;' +typedefs['signed_char']='typedef signed char signed_char;' +typedefs['long_long']="""\ +#ifdef _WIN32 +typedef __int64 long_long; +#else +typedef long long long_long; +typedef unsigned long long unsigned_long_long; +#endif +""" +typedefs['insinged_long_long']="""\ +#ifdef _WIN32 +typedef __uint64 long_long; +#else +typedef unsigned long long unsigned_long_long; +#endif +""" +typedefs['long_double']="""\ +#ifndef _LONG_DOUBLE +typedef long double long_double; +#endif +""" +typedefs['complex_long_double']='typedef struct {long double r,i;} complex_long_double;' +typedefs['complex_float']='typedef struct {float r,i;} complex_float;' +typedefs['complex_double']='typedef struct {double r,i;} complex_double;' +typedefs['string']="""typedef char * string;""" + + +############### CPP macros #################### +cppmacros['CFUNCSMESS']="""\ +#ifdef DEBUGCFUNCS +#define CFUNCSMESS(mess) fprintf(stderr,\"debug-capi:\"mess); +#define CFUNCSMESSPY(mess,obj) CFUNCSMESS(mess) \\ +\tPyObject_Print((PyObject *)obj,stderr,Py_PRINT_RAW);\\ +\tfprintf(stderr,\"\\n\"); +#else +#define CFUNCSMESS(mess) +#define CFUNCSMESSPY(mess,obj) +#endif +""" +cppmacros['F_FUNC']="""\ +#if defined(PREPEND_FORTRAN) +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) _##F +#else +#define F_FUNC(f,F) _##f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) _##F##_ +#else +#define F_FUNC(f,F) _##f##_ +#endif +#endif +#else +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) F +#else +#define F_FUNC(f,F) f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) F##_ +#else +#define F_FUNC(f,F) f##_ +#endif +#endif +#endif +#if defined(UNDERSCORE_G77) +#define F_FUNC_US(f,F) F_FUNC(f##_,F##_) +#else +#define F_FUNC_US(f,F) F_FUNC(f,F) +#endif +""" +cppmacros['F_WRAPPEDFUNC']="""\ +#if defined(PREPEND_FORTRAN) +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) _F2PYWRAP##F +#else +#define F_WRAPPEDFUNC(f,F) _f2pywrap##f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) _F2PYWRAP##F##_ +#else +#define F_WRAPPEDFUNC(f,F) _f2pywrap##f##_ +#endif +#endif +#else +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) F2PYWRAP##F +#else +#define F_WRAPPEDFUNC(f,F) f2pywrap##f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_WRAPPEDFUNC(f,F) F2PYWRAP##F##_ +#else +#define F_WRAPPEDFUNC(f,F) f2pywrap##f##_ +#endif +#endif +#endif +#if defined(UNDERSCORE_G77) +#define F_WRAPPEDFUNC_US(f,F) F_WRAPPEDFUNC(f##_,F##_) +#else +#define F_WRAPPEDFUNC_US(f,F) F_WRAPPEDFUNC(f,F) +#endif +""" +cppmacros['F_MODFUNC']="""\ +#if defined(F90MOD2CCONV1) /*E.g. Compaq Fortran */ +#if defined(NO_APPEND_FORTRAN) +#define F_MODFUNCNAME(m,f) $ ## m ## $ ## f +#else +#define F_MODFUNCNAME(m,f) $ ## m ## $ ## f ## _ +#endif +#endif + +#if defined(F90MOD2CCONV2) /*E.g. IBM XL Fortran, not tested though */ +#if defined(NO_APPEND_FORTRAN) +#define F_MODFUNCNAME(m,f) __ ## m ## _MOD_ ## f +#else +#define F_MODFUNCNAME(m,f) __ ## m ## _MOD_ ## f ## _ +#endif +#endif + +#if defined(F90MOD2CCONV3) /*E.g. MIPSPro Compilers */ +#if defined(NO_APPEND_FORTRAN) +#define F_MODFUNCNAME(m,f) f ## .in. ## m +#else +#define F_MODFUNCNAME(m,f) f ## .in. ## m ## _ +#endif +#endif +/* +#if defined(UPPERCASE_FORTRAN) +#define F_MODFUNC(m,M,f,F) F_MODFUNCNAME(M,F) +#else +#define F_MODFUNC(m,M,f,F) F_MODFUNCNAME(m,f) +#endif +*/ + +#define F_MODFUNC(m,f) (*(f2pymodstruct##m##.##f)) +""" +cppmacros['SWAPUNSAFE']="""\ +#define SWAP(a,b) (size_t)(a) = ((size_t)(a) ^ (size_t)(b));\\ + (size_t)(b) = ((size_t)(a) ^ (size_t)(b));\\ + (size_t)(a) = ((size_t)(a) ^ (size_t)(b)) +""" +cppmacros['SWAP']="""\ +#define SWAP(a,b,t) {\\ +\tt *c;\\ +\tc = a;\\ +\ta = b;\\ +\tb = c;} +""" +#cppmacros['ISCONTIGUOUS']='#define ISCONTIGUOUS(m) ((m)->flags & CONTIGUOUS)' +cppmacros['PRINTPYOBJERR']="""\ +#define PRINTPYOBJERR(obj)\\ +\tfprintf(stderr,\"#modulename#.error is related to \");\\ +\tPyObject_Print((PyObject *)obj,stderr,Py_PRINT_RAW);\\ +\tfprintf(stderr,\"\\n\"); +""" +cppmacros['MINMAX']="""\ +#ifndef MAX +#define MAX(a,b) ((a > b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a < b) ? (a) : (b)) +#endif +""" +cppmacros['len..']="""\ +#define rank(var) var ## _Rank +#define shape(var,dim) var ## _Dims[dim] +#define old_rank(var) (((PyArrayObject *)(capi_ ## var ## _tmp))->nd) +#define old_shape(var,dim) (((PyArrayObject *)(capi_ ## var ## _tmp))->dimensions[dim]) +#define fshape(var,dim) shape(var,rank(var)-dim-1) +#define len(var) shape(var,0) +#define flen(var) fshape(var,0) +#define size(var) PyArray_SIZE((PyArrayObject *)(capi_ ## var ## _tmp)) +/* #define index(i) capi_i ## i */ +#define slen(var) capi_ ## var ## _len +""" + +cppmacros['pyobj_from_char1']='#define pyobj_from_char1(v) (PyInt_FromLong(v))' +cppmacros['pyobj_from_short1']='#define pyobj_from_short1(v) (PyInt_FromLong(v))' +needs['pyobj_from_int1']=['signed_char'] +cppmacros['pyobj_from_int1']='#define pyobj_from_int1(v) (PyInt_FromLong(v))' +cppmacros['pyobj_from_long1']='#define pyobj_from_long1(v) (PyLong_FromLong(v))' +needs['pyobj_from_long_long1']=['long_long'] +cppmacros['pyobj_from_long_long1']="""\ +#ifdef HAVE_LONG_LONG +#define pyobj_from_long_long1(v) (PyLong_FromLongLong(v)) +#else +#warning HAVE_LONG_LONG is not available. Redefining pyobj_from_long_long. +#define pyobj_from_long_long1(v) (PyLong_FromLong(v)) +#endif +""" +needs['pyobj_from_long_double1']=['long_double'] +cppmacros['pyobj_from_long_double1']='#define pyobj_from_long_double1(v) (PyFloat_FromDouble(v))' +cppmacros['pyobj_from_double1']='#define pyobj_from_double1(v) (PyFloat_FromDouble(v))' +cppmacros['pyobj_from_float1']='#define pyobj_from_float1(v) (PyFloat_FromDouble(v))' +needs['pyobj_from_complex_long_double1']=['complex_long_double'] +cppmacros['pyobj_from_complex_long_double1']='#define pyobj_from_complex_long_double1(v) (PyComplex_FromDoubles(v.r,v.i))' +needs['pyobj_from_complex_double1']=['complex_double'] +cppmacros['pyobj_from_complex_double1']='#define pyobj_from_complex_double1(v) (PyComplex_FromDoubles(v.r,v.i))' +needs['pyobj_from_complex_float1']=['complex_float'] +cppmacros['pyobj_from_complex_float1']='#define pyobj_from_complex_float1(v) (PyComplex_FromDoubles(v.r,v.i))' +needs['pyobj_from_string1']=['string'] +cppmacros['pyobj_from_string1']='#define pyobj_from_string1(v) (PyString_FromString((char *)v))' +needs['TRYPYARRAYTEMPLATE']=['PRINTPYOBJERR'] +cppmacros['TRYPYARRAYTEMPLATE']="""\ +/* New SciPy */ +#define TRYPYARRAYTEMPLATECHAR case PyArray_STRING: *(char *)(arr->data)=*v; break; +#define TRYPYARRAYTEMPLATELONG case PyArray_LONG: *(long *)(arr->data)=*v; break; +#define TRYPYARRAYTEMPLATEOBJECT case PyArray_OBJECT: (arr->descr->f->setitem)(pyobj_from_ ## ctype ## 1(*v),arr->data); break; + +#define TRYPYARRAYTEMPLATE(ctype,typecode) \\ + PyArrayObject *arr = NULL;\\ + if (!obj) return -2;\\ + if (!PyArray_Check(obj)) return -1;\\ + if (!(arr=(PyArrayObject *)obj)) {fprintf(stderr,\"TRYPYARRAYTEMPLATE:\");PRINTPYOBJERR(obj);return 0;}\\ + if (arr->descr->type==typecode) {*(ctype *)(arr->data)=*v; return 1;}\\ + switch (arr->descr->type_num) {\\ + case PyArray_DOUBLE: *(double *)(arr->data)=*v; break;\\ + case PyArray_INT: *(int *)(arr->data)=*v; break;\\ + case PyArray_LONG: *(long *)(arr->data)=*v; break;\\ + case PyArray_FLOAT: *(float *)(arr->data)=*v; break;\\ + case PyArray_CDOUBLE: *(double *)(arr->data)=*v; break;\\ + case PyArray_CFLOAT: *(float *)(arr->data)=*v; break;\\ + case PyArray_BOOL: *(Bool *)(arr->data)=(*v!=0); break;\\ + case PyArray_UBYTE: *(unsigned char *)(arr->data)=*v; break;\\ + case PyArray_BYTE: *(signed char *)(arr->data)=*v; break;\\ + case PyArray_SHORT: *(short *)(arr->data)=*v; break;\\ + case PyArray_USHORT: *(ushort *)(arr->data)=*v; break;\\ + case PyArray_UINT: *(uint *)(arr->data)=*v; break;\\ + case PyArray_ULONG: *(ulong *)(arr->data)=*v; break;\\ + case PyArray_LONGLONG: *(longlong *)(arr->data)=*v; break;\\ + case PyArray_ULONGLONG: *(ulonglong *)(arr->data)=*v; break;\\ + case PyArray_LONGDOUBLE: *(longdouble *)(arr->data)=*v; break;\\ + case PyArray_CLONGDOUBLE: *(longdouble *)(arr->data)=*v; break;\\ + case PyArray_OBJECT: (arr->descr->f->setitem)(pyobj_from_ ## ctype ## 1(*v),arr->data, arr); break;\\ + default: return -2;\\ + };\\ + return 1 +""" + +needs['TRYCOMPLEXPYARRAYTEMPLATE']=['PRINTPYOBJERR'] +cppmacros['TRYCOMPLEXPYARRAYTEMPLATE']="""\ +#define TRYCOMPLEXPYARRAYTEMPLATEOBJECT case PyArray_OBJECT: (arr->descr->f->setitem)(pyobj_from_complex_ ## ctype ## 1((*v)),arr->data, arr); break; +#define TRYCOMPLEXPYARRAYTEMPLATE(ctype,typecode)\\ + PyArrayObject *arr = NULL;\\ + if (!obj) return -2;\\ + if (!PyArray_Check(obj)) return -1;\\ + if (!(arr=(PyArrayObject *)obj)) {fprintf(stderr,\"TRYCOMPLEXPYARRAYTEMPLATE:\");PRINTPYOBJERR(obj);return 0;}\\ + if (arr->descr->type==typecode) {\\ + *(ctype *)(arr->data)=(*v).r;\\ + *(ctype *)(arr->data+sizeof(ctype))=(*v).i;\\ + return 1;\\ + }\\ + switch (arr->descr->type_num) {\\ + case PyArray_CDOUBLE: *(double *)(arr->data)=(*v).r;*(double *)(arr->data+sizeof(double))=(*v).i;break;\\ + case PyArray_CFLOAT: *(float *)(arr->data)=(*v).r;*(float *)(arr->data+sizeof(float))=(*v).i;break;\\ + case PyArray_DOUBLE: *(double *)(arr->data)=(*v).r; break;\\ + case PyArray_LONG: *(long *)(arr->data)=(*v).r; break;\\ + case PyArray_FLOAT: *(float *)(arr->data)=(*v).r; break;\\ + case PyArray_INT: *(int *)(arr->data)=(*v).r; break;\\ + case PyArray_SHORT: *(short *)(arr->data)=(*v).r; break;\\ + case PyArray_UBYTE: *(unsigned char *)(arr->data)=(*v).r; break;\\ + case PyArray_BYTE: *(signed char *)(arr->data)=(*v).r; break;\\ + case PyArray_BOOL: *(Bool *)(arr->data)=((*v).r!=0 && (*v).i!=0)); break;\\ + case PyArray_UBYTE: *(unsigned char *)(arr->data)=(*v).r; break;\\ + case PyArray_BYTE: *(signed char *)(arr->data)=(*v).r; break;\\ + case PyArray_SHORT: *(short *)(arr->data)=(*v).r; break;\\ + case PyArray_USHORT: *(ushort *)(arr->data)=(*v).r; break;\\ + case PyArray_UINT: *(uint *)(arr->data)=(*v).r; break;\\ + case PyArray_ULONG: *(ulong *)(arr->data)=(*v).r; break;\\ + case PyArray_LONGLONG: *(longlong *)(arr->data)=(*v).r; break;\\ + case PyArray_ULONGLONG: *(ulonglong *)(arr->data)=(*v).r; break;\\ + case PyArray_LONGDOUBLE: *(longdouble *)(arr->data)=(*v).r; break;\\ + case PyArray_CLONGDOUBLE: *(longdouble *)(arr->data)=(*v).r;*(longdouble *)(arr->data+sizeof(longdouble))=(*v).i;break;\\ + case PyArray_OBJECT: (arr->descr->f->setitem)(pyobj_from_complex_ ## ctype ## 1((*v)),arr->data, arr); break;\\ + default: return -2;\\ + };\\ + return -1; +""" +## cppmacros['NUMFROMARROBJ']="""\ +## #define NUMFROMARROBJ(typenum,ctype) \\ +## \tif (PyArray_Check(obj)) arr = (PyArrayObject *)obj;\\ +## \telse arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,typenum,0,0);\\ +## \tif (arr) {\\ +## \t\tif (arr->descr->type_num==PyArray_OBJECT) {\\ +## \t\t\tif (!ctype ## _from_pyobj(v,(arr->descr->getitem)(arr->data),\"\"))\\ +## \t\t\tgoto capi_fail;\\ +## \t\t} else {\\ +## \t\t\t(arr->descr->cast[typenum])(arr->data,1,(char*)v,1,1);\\ +## \t\t}\\ +## \t\tif ((PyObject *)arr != obj) { Py_DECREF(arr); }\\ +## \t\treturn 1;\\ +## \t} +## """ +## #XXX: Note that CNUMFROMARROBJ is identical with NUMFROMARROBJ +## cppmacros['CNUMFROMARROBJ']="""\ +## #define CNUMFROMARROBJ(typenum,ctype) \\ +## \tif (PyArray_Check(obj)) arr = (PyArrayObject *)obj;\\ +## \telse arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,typenum,0,0);\\ +## \tif (arr) {\\ +## \t\tif (arr->descr->type_num==PyArray_OBJECT) {\\ +## \t\t\tif (!ctype ## _from_pyobj(v,(arr->descr->getitem)(arr->data),\"\"))\\ +## \t\t\tgoto capi_fail;\\ +## \t\t} else {\\ +## \t\t\t(arr->descr->cast[typenum])((void *)(arr->data),1,(void *)(v),1,1);\\ +## \t\t}\\ +## \t\tif ((PyObject *)arr != obj) { Py_DECREF(arr); }\\ +## \t\treturn 1;\\ +## \t} +## """ + + +needs['GETSTRFROMPYTUPLE']=['STRINGCOPYN','PRINTPYOBJERR'] +cppmacros['GETSTRFROMPYTUPLE']="""\ +#define GETSTRFROMPYTUPLE(tuple,index,str,len) {\\ +\t\tPyObject *rv_cb_str = PyTuple_GetItem((tuple),(index));\\ +\t\tif (rv_cb_str == NULL)\\ +\t\t\tgoto capi_fail;\\ +\t\tif (PyString_Check(rv_cb_str)) {\\ +\t\t\tstr[len-1]='\\0';\\ +\t\t\tSTRINGCOPYN((str),PyString_AS_STRING((PyStringObject*)rv_cb_str),(len));\\ +\t\t} else {\\ +\t\t\tPRINTPYOBJERR(rv_cb_str);\\ +\t\t\tPyErr_SetString(#modulename#_error,\"string object expected\");\\ +\t\t\tgoto capi_fail;\\ +\t\t}\\ +\t} +""" +cppmacros['GETSCALARFROMPYTUPLE']="""\ +#define GETSCALARFROMPYTUPLE(tuple,index,var,ctype,mess) {\\ +\t\tif ((capi_tmp = PyTuple_GetItem((tuple),(index)))==NULL) goto capi_fail;\\ +\t\tif (!(ctype ## _from_pyobj((var),capi_tmp,mess)))\\ +\t\t\tgoto capi_fail;\\ +\t} +""" + +needs['MEMCOPY']=['string.h'] +cppmacros['MEMCOPY']="""\ +#define MEMCOPY(to,from,n)\\ +\tif ((memcpy(to,from,n)) == NULL) {\\ +\t\tPyErr_SetString(PyExc_MemoryError, \"memcpy failed\");\\ +\t\tgoto capi_fail;\\ +\t} +""" +cppmacros['STRINGMALLOC']="""\ +#define STRINGMALLOC(str,len)\\ +\tif ((str = (string)malloc(sizeof(char)*(len+1))) == NULL) {\\ +\t\tPyErr_SetString(PyExc_MemoryError, \"out of memory\");\\ +\t\tgoto capi_fail;\\ +\t} else {\\ +\t\t(str)[len] = '\\0';\\ +\t} +""" +cppmacros['STRINGFREE']="""\ +#define STRINGFREE(str)\\ +\tif (!(str == NULL)) free(str); +""" +needs['STRINGCOPYN']=['string.h'] +cppmacros['STRINGCOPYN']="""\ +#define STRINGCOPYN(to,from,n)\\ +\tif ((strncpy(to,from,sizeof(char)*(n))) == NULL) {\\ +\t\tPyErr_SetString(PyExc_MemoryError, \"strncpy failed\");\\ +\t\tgoto capi_fail;\\ +\t} else if (strlen(to)<(n)) {\\ +\t\tmemset((to)+strlen(to), ' ', (n)-strlen(to));\\ +\t} /* Padding with spaces instead of nulls. */ +""" +needs['STRINGCOPY']=['string.h'] +cppmacros['STRINGCOPY']="""\ +#define STRINGCOPY(to,from)\\ +\tif ((strcpy(to,from)) == NULL) {\\ +\t\tPyErr_SetString(PyExc_MemoryError, \"strcpy failed\");\\ +\t\tgoto capi_fail;\\ +\t} +""" +cppmacros['CHECKGENERIC']="""\ +#define CHECKGENERIC(check,tcheck,name) \\ +\tif (!(check)) {\\ +\t\tPyErr_SetString(#modulename#_error,\"(\"tcheck\") failed for \"name);\\ +\t\t/*goto capi_fail;*/\\ +\t} else """ +cppmacros['CHECKARRAY']="""\ +#define CHECKARRAY(check,tcheck,name) \\ +\tif (!(check)) {\\ +\t\tPyErr_SetString(#modulename#_error,\"(\"tcheck\") failed for \"name);\\ +\t\t/*goto capi_fail;*/\\ +\t} else """ +cppmacros['CHECKSTRING']="""\ +#define CHECKSTRING(check,tcheck,name,show,var)\\ +\tif (!(check)) {\\ +\t\tPyErr_SetString(#modulename#_error,\"(\"tcheck\") failed for \"name);\\ +\t\tfprintf(stderr,show\"\\n\",slen(var),var);\\ +\t\t/*goto capi_fail;*/\\ +\t} else """ +cppmacros['CHECKSCALAR']="""\ +#define CHECKSCALAR(check,tcheck,name,show,var)\\ +\tif (!(check)) {\\ +\t\tPyErr_SetString(#modulename#_error,\"(\"tcheck\") failed for \"name);\\ +\t\tfprintf(stderr,show\"\\n\",var);\\ +\t\t/*goto capi_fail;*/\\ +\t} else """ +## cppmacros['CHECKDIMS']="""\ +## #define CHECKDIMS(dims,rank) \\ +## \tfor (int i=0;i<(rank);i++)\\ +## \t\tif (dims[i]<0) {\\ +## \t\t\tfprintf(stderr,\"Unspecified array argument requires a complete dimension specification.\\n\");\\ +## \t\t\tgoto capi_fail;\\ +## \t\t} +## """ +cppmacros['ARRSIZE']='#define ARRSIZE(dims,rank) (_PyArray_multiply_list(dims,rank))' +cppmacros['OLDPYNUM']="""\ +#ifdef OLDPYNUM +#error You need to intall Numeric Python version 13 or higher. Get it from http:/sourceforge.net/project/?group_id=1369 +#endif +""" +################# C functions ############### + +cfuncs['calcarrindex']="""\ +static int calcarrindex(int *i,PyArrayObject *arr) { +\tint k,ii = i[0]; +\tfor (k=1; k < arr->nd; k++) +\t\tii += (ii*(arr->dimensions[k] - 1)+i[k]); /* assuming contiguous arr */ +\treturn ii; +}""" +cfuncs['calcarrindextr']="""\ +static int calcarrindextr(int *i,PyArrayObject *arr) { +\tint k,ii = i[arr->nd-1]; +\tfor (k=1; k < arr->nd; k++) +\t\tii += (ii*(arr->dimensions[arr->nd-k-1] - 1)+i[arr->nd-k-1]); /* assuming contiguous arr */ +\treturn ii; +}""" +cfuncs['forcomb']="""\ +static struct { int nd;intp *d;int *i,*i_tr,tr; } forcombcache; +static int initforcomb(intp *dims,int nd,int tr) { + int k; + if (dims==NULL) return 0; + if (nd<0) return 0; + forcombcache.nd = nd; + forcombcache.d = dims; + forcombcache.tr = tr; + if ((forcombcache.i = (int *)malloc(sizeof(int)*nd))==NULL) return 0; + if ((forcombcache.i_tr = (int *)malloc(sizeof(int)*nd))==NULL) return 0; + for (k=1;k<nd;k++) { + forcombcache.i[k] = forcombcache.i_tr[nd-k-1] = 0; + } + forcombcache.i[0] = forcombcache.i_tr[nd-1] = -1; + return 1; +} +static int *nextforcomb(void) { + int j,*i,*i_tr,k; + int nd=forcombcache.nd; + if ((i=forcombcache.i) == NULL) return NULL; + if ((i_tr=forcombcache.i_tr) == NULL) return NULL; + if (forcombcache.d == NULL) return NULL; + i[0]++; + if (i[0]==forcombcache.d[0]) { + j=1; + while ((j<nd) && (i[j]==forcombcache.d[j]-1)) j++; + if (j==nd) { + free(i); + free(i_tr); + return NULL; + } + for (k=0;k<j;k++) i[k] = i_tr[nd-k-1] = 0; + i[j]++; + i_tr[nd-j-1]++; + } else + i_tr[nd-1]++; + if (forcombcache.tr) return i_tr; + return i; +}""" +needs['try_pyarr_from_string']=['STRINGCOPYN','PRINTPYOBJERR','string'] +cfuncs['try_pyarr_from_string']="""\ +static int try_pyarr_from_string(PyObject *obj,const string str) { +\tPyArrayObject *arr = NULL; +\tif (PyArray_Check(obj) && (!((arr = (PyArrayObject *)obj) == NULL))) +\t\t{ STRINGCOPYN(arr->data,str,PyArray_NBYTES(arr)); } +\treturn 1; +capi_fail: +\tPRINTPYOBJERR(obj); +\tPyErr_SetString(#modulename#_error,\"try_pyarr_from_string failed\"); +\treturn 0; +} +""" +needs['string_from_pyobj']=['string','STRINGMALLOC','STRINGCOPYN'] +cfuncs['string_from_pyobj']="""\ +static int string_from_pyobj(string *str,int *len,const string inistr,PyObject *obj,const char *errmess) { +\tPyArrayObject *arr = NULL; +\tPyObject *tmp = NULL; +#ifdef DEBUGCFUNCS +fprintf(stderr,\"string_from_pyobj(str='%s',len=%d,inistr='%s',obj=%p)\\n\",(char*)str,*len,(char *)inistr,obj); +#endif +\tif (obj == Py_None) { +\t\tif (*len == -1) +\t\t\t*len = strlen(inistr); /* Will this cause problems? */ +\t\tSTRINGMALLOC(*str,*len); +\t\tSTRINGCOPYN(*str,inistr,*len); +\t\treturn 1; +\t} +\tif (PyArray_Check(obj)) { +\t\tif ((arr = (PyArrayObject *)obj) == NULL) +\t\t\tgoto capi_fail; +\t\tif (!ISCONTIGUOUS(arr)) { +\t\t\tPyErr_SetString(PyExc_ValueError,\"array object is non-contiguous.\"); +\t\t\tgoto capi_fail; +\t\t} +\t\tif (*len == -1) +\t\t\t*len = (arr->descr->elsize)*PyArray_SIZE(arr); +\t\tSTRINGMALLOC(*str,*len); +\t\tSTRINGCOPYN(*str,arr->data,*len); +\t\treturn 1; +\t} +\tif (PyString_Check(obj)) { +\t\ttmp = obj; +\t\tPy_INCREF(tmp); +\t} +\telse +\t\ttmp = PyObject_Str(obj); +\tif (tmp == NULL) goto capi_fail; +\tif (*len == -1) +\t\t*len = PyString_GET_SIZE(tmp); +\tSTRINGMALLOC(*str,*len); +\tSTRINGCOPYN(*str,PyString_AS_STRING(tmp),*len); +\tPy_DECREF(tmp); +\treturn 1; +capi_fail: +\tPy_XDECREF(tmp); +\t{ +\t\tPyObject* err = PyErr_Occurred(); +\t\tif (err==NULL) err = #modulename#_error; +\t\tPyErr_SetString(err,errmess); +\t} +\treturn 0; +} +""" +needs['char_from_pyobj']=['int_from_pyobj'] +cfuncs['char_from_pyobj']="""\ +static int char_from_pyobj(char* v,PyObject *obj,const char *errmess) { +\tint i=0; +\tif (int_from_pyobj(&i,obj,errmess)) { +\t\t*v = (char)i; +\t\treturn 1; +\t} +\treturn 0; +} +""" +needs['signed_char_from_pyobj']=['int_from_pyobj','signed_char'] +cfuncs['signed_char_from_pyobj']="""\ +static int signed_char_from_pyobj(signed_char* v,PyObject *obj,const char *errmess) { +\tint i=0; +\tif (int_from_pyobj(&i,obj,errmess)) { +\t\t*v = (signed_char)i; +\t\treturn 1; +\t} +\treturn 0; +} +""" +needs['short_from_pyobj']=['int_from_pyobj'] +cfuncs['short_from_pyobj']="""\ +static int short_from_pyobj(short* v,PyObject *obj,const char *errmess) { +\tint i=0; +\tif (int_from_pyobj(&i,obj,errmess)) { +\t\t*v = (short)i; +\t\treturn 1; +\t} +\treturn 0; +} +""" +cfuncs['int_from_pyobj']="""\ +static int int_from_pyobj(int* v,PyObject *obj,const char *errmess) { +\tPyObject* tmp = NULL; +\tif (PyInt_Check(obj)) { +\t\t*v = (int)PyInt_AS_LONG(obj); +\t\treturn 1; +\t} +\ttmp = PyNumber_Int(obj); +\tif (tmp) { +\t\t*v = PyInt_AS_LONG(tmp); +\t\tPy_DECREF(tmp); +\t\treturn 1; +\t} +\tif (PyComplex_Check(obj)) +\t\ttmp = PyObject_GetAttrString(obj,\"real\"); +\telse if (PyString_Check(obj)) +\t\t/*pass*/; +\telse if (PySequence_Check(obj)) +\t\ttmp = PySequence_GetItem(obj,0); +\tif (tmp) { +\t\tPyErr_Clear(); +\t\tif (int_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} +\t\tPy_DECREF(tmp); +\t} +\t{ +\t\tPyObject* err = PyErr_Occurred(); +\t\tif (err==NULL) err = #modulename#_error; +\t\tPyErr_SetString(err,errmess); +\t} +\treturn 0; +} +""" +cfuncs['long_from_pyobj']="""\ +static int long_from_pyobj(long* v,PyObject *obj,const char *errmess) { +\tPyObject* tmp = NULL; +\tif (PyInt_Check(obj)) { +\t\t*v = PyInt_AS_LONG(obj); +\t\treturn 1; +\t} +\ttmp = PyNumber_Int(obj); +\tif (tmp) { +\t\t*v = PyInt_AS_LONG(tmp); +\t\tPy_DECREF(tmp); +\t\treturn 1; +\t} +\tif (PyComplex_Check(obj)) +\t\ttmp = PyObject_GetAttrString(obj,\"real\"); +\telse if (PyString_Check(obj)) +\t\t/*pass*/; +\telse if (PySequence_Check(obj)) +\t\ttmp = PySequence_GetItem(obj,0); +\tif (tmp) { +\t\tPyErr_Clear(); +\t\tif (long_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} +\t\tPy_DECREF(tmp); +\t} +\t{ +\t\tPyObject* err = PyErr_Occurred(); +\t\tif (err==NULL) err = #modulename#_error; +\t\tPyErr_SetString(err,errmess); +\t} +\treturn 0; +} +""" +needs['long_long_from_pyobj']=['long_long'] +cfuncs['long_long_from_pyobj']="""\ +static int long_long_from_pyobj(long_long* v,PyObject *obj,const char *errmess) { +\tPyObject* tmp = NULL; +\tif (PyLong_Check(obj)) { +\t\t*v = PyLong_AsLongLong(obj); +\t\treturn (!PyErr_Occurred()); +\t} +\tif (PyInt_Check(obj)) { +\t\t*v = (long_long)PyInt_AS_LONG(obj); +\t\treturn 1; +\t} +\ttmp = PyNumber_Long(obj); +\tif (tmp) { +\t\t*v = PyLong_AsLongLong(tmp); +\t\tPy_DECREF(tmp); +\t\treturn (!PyErr_Occurred()); +\t} +\tif (PyComplex_Check(obj)) +\t\ttmp = PyObject_GetAttrString(obj,\"real\"); +\telse if (PyString_Check(obj)) +\t\t/*pass*/; +\telse if (PySequence_Check(obj)) +\t\ttmp = PySequence_GetItem(obj,0); +\tif (tmp) { +\t\tPyErr_Clear(); +\t\tif (long_long_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} +\t\tPy_DECREF(tmp); +\t} +\t{ +\t\tPyObject* err = PyErr_Occurred(); +\t\tif (err==NULL) err = #modulename#_error; +\t\tPyErr_SetString(err,errmess); +\t} +\treturn 0; +} +""" +needs['long_double_from_pyobj']=['double_from_pyobj','long_double'] +cfuncs['long_double_from_pyobj']="""\ +static int long_double_from_pyobj(long_double* v,PyObject *obj,const char *errmess) { +\tdouble d=0; +\tif (PyArray_CheckScalar(obj)){ +\t\tif PyArray_IsScalar(obj, LongDouble) { +\t\t\tPyArray_ScalarAsCtype(obj, v); +\t\t\treturn 1; +\t\t} +\t\telse if (PyArray_Check(obj) && PyArray_TYPE(obj)==PyArray_LONGDOUBLE) { +\t\t\t(*v) = *((longdouble *)PyArray_DATA(obj)) +\t\t\treturn 1; +\t\t} +\t} +\tif (double_from_pyobj(&d,obj,errmess)) { +\t\t*v = (long_double)d; +\t\treturn 1; +\t} +\treturn 0; +} +""" +cfuncs['double_from_pyobj']="""\ +static int double_from_pyobj(double* v,PyObject *obj,const char *errmess) { +\tPyObject* tmp = NULL; +\tif (PyFloat_Check(obj)) { +#ifdef __sgi +\t\t*v = PyFloat_AsDouble(obj); +#else +\t\t*v = PyFloat_AS_DOUBLE(obj); +#endif +\t\treturn 1; +\t} +\ttmp = PyNumber_Float(obj); +\tif (tmp) { +#ifdef __sgi +\t\t*v = PyFloat_AsDouble(tmp); +#else +\t\t*v = PyFloat_AS_DOUBLE(tmp); +#endif +\t\tPy_DECREF(tmp); +\t\treturn 1; +\t} +\tif (PyComplex_Check(obj)) +\t\ttmp = PyObject_GetAttrString(obj,\"real\"); +\telse if (PyString_Check(obj)) +\t\t/*pass*/; +\telse if (PySequence_Check(obj)) +\t\ttmp = PySequence_GetItem(obj,0); +\tif (tmp) { +\t\tPyErr_Clear(); +\t\tif (double_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;} +\t\tPy_DECREF(tmp); +\t} +\t{ +\t\tPyObject* err = PyErr_Occurred(); +\t\tif (err==NULL) err = #modulename#_error; +\t\tPyErr_SetString(err,errmess); +\t} +\treturn 0; +} +""" +needs['float_from_pyobj']=['double_from_pyobj'] +cfuncs['float_from_pyobj']="""\ +static int float_from_pyobj(float* v,PyObject *obj,const char *errmess) { +\tdouble d=0.0; +\tif (double_from_pyobj(&d,obj,errmess)) { +\t\t*v = (float)d; +\t\treturn 1; +\t} +\treturn 0; +} +""" +needs['complex_long_double_from_pyobj']=['complex_long_double','long_double', + 'complex_double_from_pyobj'] +cfuncs['complex_long_double_from_pyobj']="""\ +static int complex_long_double_from_pyobj(complex_long_double* v,PyObject *obj,const char *errmess) { +\tcomplex_double cd={0.0,0.0}; +\tif (PyArray_CheckScalar(obj)){ +\t\tif PyArray_IsScalar(obj, CLongDouble) { +\t\t\tPyArray_ScalarAsCtype(obj, v); +\t\t\treturn 1; +\t\t} +\t\telse if (PyArray_Check(obj) && PyArray_TYPE(obj)==PyArray_CLONGDOUBLE) { +\t\t\t(*v).r = ((clongdouble *)PyArray_DATA(obj))->real; +\t\t\t(*v).i = ((clongdouble *)PyArray_DATA(obj))->imag; +\t\t\treturn 1; +\t\t} +\t} +\tif (complex_double_from_pyobj(&cd,obj,errmess)) { +\t\t(*v).r = (long_double)cd.r; +\t\t(*v).i = (long_double)cd.i; +\t\treturn 1; +\t} +\treturn 0; +} +""" +needs['complex_double_from_pyobj']=['complex_double'] +cfuncs['complex_double_from_pyobj']="""\ +static int complex_double_from_pyobj(complex_double* v,PyObject *obj,const char *errmess) { +\tPy_complex c; +\tif (PyComplex_Check(obj)) { +\t\tc=PyComplex_AsCComplex(obj); +\t\t(*v).r=c.real, (*v).i=c.imag; +\t\treturn 1; +\t} +\tif (PyArray_IsScalar(obj, ComplexFloating)) { +\t\tif (PyArray_IsScalar(obj, CFloat)) { +\t\t\tcfloat new; +\t\t\tPyArray_ScalarAsCtype(obj, &new); +\t\t\t(*v).r = (double)new.real; +\t\t\t(*v).i = (double)new.imag; +\t\t} +\t\telse if (PyArray_IsScalar(obj, CLongDouble)) { +\t\t\tclongdouble new; +\t\t\tPyArray_ScalarAsCtype(obj, &new); +\t\t\t(*v).r = (double)new.real; +\t\t\t(*v).i = (double)new.imag; +\t\t} +\t\telse { /* if (PyArray_IsScalar(obj, CDouble)) */ +\t\t\tPyArray_ScalarAsCtype(obj, v); +\t\t} +\t\treturn 1; +\t} +\tif (PyArray_CheckScalar(obj)) { /* 0-dim array or still array scalar */ +\t\tPyObject *arr; +\t\tif (PyArray_Check(obj)) { +\t\t\tarr = PyArray_Cast((PyArrayObject *)obj, PyArray_CDOUBLE); +\t\t} +\t\telse { +\t\t\tarr = PyArray_FromScalar(obj, PyArray_DescrFromType(PyArray_CDOUBLE)); +\t\t} +\t\tif (arr==NULL) return 0; +\t\t(*v).r = ((cdouble *)PyArray_DATA(arr))->real; +\t\t(*v).i = ((cdouble *)PyArray_DATA(arr))->imag; +\t\treturn 1; +\t} +\t/* Python does not provide PyNumber_Complex function :-( */ +\t(*v).i=0.0; +\tif (PyFloat_Check(obj)) { +#ifdef __sgi +\t\t(*v).r = PyFloat_AsDouble(obj); +#else +\t\t(*v).r = PyFloat_AS_DOUBLE(obj); +#endif +\t\treturn 1; +\t} +\tif (PyInt_Check(obj)) { +\t\t(*v).r = (double)PyInt_AS_LONG(obj); +\t\treturn 1; +\t} +\tif (PyLong_Check(obj)) { +\t\t(*v).r = PyLong_AsDouble(obj); +\t\treturn (!PyErr_Occurred()); +\t} +\tif (PySequence_Check(obj) && (!PyString_Check(obj))) { +\t\tPyObject *tmp = PySequence_GetItem(obj,0); +\t\tif (tmp) { +\t\t\tif (complex_double_from_pyobj(v,tmp,errmess)) { +\t\t\t\tPy_DECREF(tmp); +\t\t\t\treturn 1; +\t\t\t} +\t\t\tPy_DECREF(tmp); +\t\t} +\t} +\t{ +\t\tPyObject* err = PyErr_Occurred(); +\t\tif (err==NULL) +\t\t\terr = PyExc_TypeError; +\t\tPyErr_SetString(err,errmess); +\t} +\treturn 0; +} +""" +needs['complex_float_from_pyobj']=['complex_float','complex_double_from_pyobj'] +cfuncs['complex_float_from_pyobj']="""\ +static int complex_float_from_pyobj(complex_float* v,PyObject *obj,const char *errmess) { +\tcomplex_double cd={0.0,0.0}; +\tif (complex_double_from_pyobj(&cd,obj,errmess)) { +\t\t(*v).r = (float)cd.r; +\t\t(*v).i = (float)cd.i; +\t\treturn 1; +\t} +\treturn 0; +} +""" +needs['try_pyarr_from_char']=['pyobj_from_char1','TRYPYARRAYTEMPLATE'] +cfuncs['try_pyarr_from_char']='static int try_pyarr_from_char(PyObject* obj,char* v) {\n\tTRYPYARRAYTEMPLATE(char,\'c\');\n}\n' +needs['try_pyarr_from_signed_char']=['TRYPYARRAYTEMPLATE','unsigned_char'] +cfuncs['try_pyarr_from_unsigned_char']='static int try_pyarr_from_unsigned_char(PyObject* obj,unsigned_char* v) {\n\tTRYPYARRAYTEMPLATE(unsigned_char,\'b\');\n}\n' +needs['try_pyarr_from_signed_char']=['TRYPYARRAYTEMPLATE','signed_char'] +cfuncs['try_pyarr_from_signed_char']='static int try_pyarr_from_signed_char(PyObject* obj,signed_char* v) {\n\tTRYPYARRAYTEMPLATE(signed_char,\'1\');\n}\n' +needs['try_pyarr_from_short']=['pyobj_from_short1','TRYPYARRAYTEMPLATE'] +cfuncs['try_pyarr_from_short']='static int try_pyarr_from_short(PyObject* obj,short* v) {\n\tTRYPYARRAYTEMPLATE(short,\'s\');\n}\n' +needs['try_pyarr_from_int']=['pyobj_from_int1','TRYPYARRAYTEMPLATE'] +cfuncs['try_pyarr_from_int']='static int try_pyarr_from_int(PyObject* obj,int* v) {\n\tTRYPYARRAYTEMPLATE(int,\'i\');\n}\n' +needs['try_pyarr_from_long']=['pyobj_from_long1','TRYPYARRAYTEMPLATE'] +cfuncs['try_pyarr_from_long']='static int try_pyarr_from_long(PyObject* obj,long* v) {\n\tTRYPYARRAYTEMPLATE(long,\'l\');\n}\n' +needs['try_pyarr_from_long_long']=['pyobj_from_long_long1','TRYPYARRAYTEMPLATE','long_long'] +cfuncs['try_pyarr_from_long_long']='static int try_pyarr_from_long_long(PyObject* obj,long_long* v) {\n\tTRYPYARRAYTEMPLATE(long_long,\'L\');\n}\n' +needs['try_pyarr_from_float']=['pyobj_from_float1','TRYPYARRAYTEMPLATE'] +cfuncs['try_pyarr_from_float']='static int try_pyarr_from_float(PyObject* obj,float* v) {\n\tTRYPYARRAYTEMPLATE(float,\'f\');\n}\n' +needs['try_pyarr_from_double']=['pyobj_from_double1','TRYPYARRAYTEMPLATE'] +cfuncs['try_pyarr_from_double']='static int try_pyarr_from_double(PyObject* obj,double* v) {\n\tTRYPYARRAYTEMPLATE(double,\'d\');\n}\n' +needs['try_pyarr_from_complex_float']=['pyobj_from_complex_float1','TRYCOMPLEXPYARRAYTEMPLATE','complex_float'] +cfuncs['try_pyarr_from_complex_float']='static int try_pyarr_from_complex_float(PyObject* obj,complex_float* v) {\n\tTRYCOMPLEXPYARRAYTEMPLATE(float,\'F\');\n}\n' +needs['try_pyarr_from_complex_double']=['pyobj_from_complex_double1','TRYCOMPLEXPYARRAYTEMPLATE','complex_double'] +cfuncs['try_pyarr_from_complex_double']='static int try_pyarr_from_complex_double(PyObject* obj,complex_double* v) {\n\tTRYCOMPLEXPYARRAYTEMPLATE(double,\'D\');\n}\n' + +needs['create_cb_arglist']=['CFUNCSMESS','PRINTPYOBJERR','MINMAX'] +cfuncs['create_cb_arglist']="""\ +static int create_cb_arglist(PyObject* fun,PyTupleObject* xa,const int maxnofargs,const int nofoptargs,int *nofargs,PyTupleObject **args,const char *errmess) { +\tPyObject *tmp = NULL; +\tPyObject *tmp_fun = NULL; +\tint tot,opt,ext,siz,i,di=0; +\tCFUNCSMESS(\"create_cb_arglist\\n\"); +\ttot=opt=ext=siz=0; +\t/* Get the total number of arguments */ +\tif (PyFunction_Check(fun)) +\t\ttmp_fun = fun; +\telse { +\t\tdi = 1; +\t\tif (PyObject_HasAttrString(fun,\"im_func\")) { +\t\t\ttmp_fun = PyObject_GetAttrString(fun,\"im_func\"); +\t\t} +\t\telse if (PyObject_HasAttrString(fun,\"__call__\")) { +\t\t\ttmp = PyObject_GetAttrString(fun,\"__call__\"); +\t\t\tif (PyObject_HasAttrString(tmp,\"im_func\")) +\t\t\t\ttmp_fun = PyObject_GetAttrString(tmp,\"im_func\"); +\t\t\telse { +\t\t\t\ttmp_fun = fun; /* built-in function */ +\t\t\t\ttot = maxnofargs; +\t\t\t\tif (xa != NULL) +\t\t\t\t\ttot += PyTuple_Size((PyObject *)xa); +\t\t\t} +\t\t\tPy_XDECREF(tmp); +\t\t} +\t\telse if (PyFortran_Check(fun) || PyFortran_Check1(fun)) { +\t\t\ttot = maxnofargs; +\t\t\tif (xa != NULL) +\t\t\t\ttot += PyTuple_Size((PyObject *)xa); +\t\t\ttmp_fun = fun; +\t\t} +\t\telse if (PyCObject_Check(fun)) { +\t\t\ttot = maxnofargs; +\t\t\tif (xa != NULL) +\t\t\t\text = PyTuple_Size((PyObject *)xa); +\t\t\tif(ext>0) { +\t\t\t\tfprintf(stderr,\"extra arguments tuple cannot be used with CObject call-back\\n\"); +\t\t\t\tgoto capi_fail; +\t\t\t} +\t\t\ttmp_fun = fun; +\t\t} +\t} +if (tmp_fun==NULL) { +fprintf(stderr,\"Call-back argument must be function|instance|instance.__call__|f2py-function but got %s.\\n\",(fun==NULL?\"NULL\":fun->ob_type->tp_name)); +goto capi_fail; +} +\tif (PyObject_HasAttrString(tmp_fun,\"func_code\")) { +\t\tif (PyObject_HasAttrString(tmp = PyObject_GetAttrString(tmp_fun,\"func_code\"),\"co_argcount\")) +\t\t\ttot = PyInt_AsLong(PyObject_GetAttrString(tmp,\"co_argcount\")) - di; +\t\tPy_XDECREF(tmp); +\t} +\t/* Get the number of optional arguments */ +\tif (PyObject_HasAttrString(tmp_fun,\"func_defaults\")) +\t\tif (PyTuple_Check(tmp = PyObject_GetAttrString(tmp_fun,\"func_defaults\"))) +\t\t\topt = PyTuple_Size(tmp); +\t\tPy_XDECREF(tmp); +\t/* Get the number of extra arguments */ +\tif (xa != NULL) +\t\text = PyTuple_Size((PyObject *)xa); +\t/* Calculate the size of call-backs argument list */ +\tsiz = MIN(maxnofargs+ext,tot); +\t*nofargs = MAX(0,siz-ext); +#ifdef DEBUGCFUNCS +\tfprintf(stderr,\"debug-capi:create_cb_arglist:maxnofargs(-nofoptargs),tot,opt,ext,siz,nofargs=%d(-%d),%d,%d,%d,%d,%d\\n\",maxnofargs,nofoptargs,tot,opt,ext,siz,*nofargs); +#endif +\tif (siz<tot-opt) { +\t\tfprintf(stderr,\"create_cb_arglist: Failed to build argument list (siz) with enough arguments (tot-opt) required by user-supplied function (siz,tot,opt=%d,%d,%d).\\n\",siz,tot,opt); +\t\tgoto capi_fail; +\t} +\t/* Initialize argument list */ +\t*args = (PyTupleObject *)PyTuple_New(siz); +\tfor (i=0;i<*nofargs;i++) { +\t\tPy_INCREF(Py_None); +\t\tPyTuple_SET_ITEM((PyObject *)(*args),i,Py_None); +\t} +\tif (xa != NULL) +\t\tfor (i=(*nofargs);i<siz;i++) { +\t\t\ttmp = PyTuple_GetItem((PyObject *)xa,i-(*nofargs)); +\t\t\tPy_INCREF(tmp); +\t\t\tPyTuple_SET_ITEM(*args,i,tmp); +\t\t} +\tCFUNCSMESS(\"create_cb_arglist-end\\n\"); +\treturn 1; +capi_fail: +\tif ((PyErr_Occurred())==NULL) +\t\tPyErr_SetString(#modulename#_error,errmess); +\treturn 0; +} +""" + +def buildcfuncs(): + from capi_maps import c2capi_map + for k in c2capi_map.keys(): + m='pyarr_from_p_%s1'%k + cppmacros[m]='#define %s(v) (PyArray_SimpleNewFromData(0,NULL,%s,(char *)v))'%(m,c2capi_map[k]) + k='string' + m='pyarr_from_p_%s1'%k + cppmacros[m]='#define %s(v,dims) (PyArray_SimpleNewFromData(1,dims,PyArray_CHAR,(char *)v))'%(m) + + +############ Auxiliary functions for sorting needs ################### + +def append_needs(need,flag=1): + global outneeds,needs + if type(need)==types.ListType: + for n in need: + append_needs(n,flag) + elif type(need)==types.StringType: + if not need: return + if includes0.has_key(need): n = 'includes0' + elif includes.has_key(need): n = 'includes' + elif typedefs.has_key(need): n = 'typedefs' + elif typedefs_generated.has_key(need): n = 'typedefs_generated' + elif cppmacros.has_key(need): n = 'cppmacros' + elif cfuncs.has_key(need): n = 'cfuncs' + elif callbacks.has_key(need): n = 'callbacks' + elif f90modhooks.has_key(need): n = 'f90modhooks' + elif commonhooks.has_key(need): n = 'commonhooks' + else: + errmess('append_needs: unknown need %s\n'%(`need`)) + return + if need in outneeds[n]: return + if flag: + tmp={} + if needs.has_key(need): + for nn in needs[need]: + t=append_needs(nn,0) + if type(t)==types.DictType: + for nnn in t.keys(): + if tmp.has_key(nnn): tmp[nnn]=tmp[nnn]+t[nnn] + else: tmp[nnn]=t[nnn] + for nn in tmp.keys(): + for nnn in tmp[nn]: + if nnn not in outneeds[nn]: + outneeds[nn]=[nnn]+outneeds[nn] + outneeds[n].append(need) + else: + tmp={} + if needs.has_key(need): + for nn in needs[need]: + t=append_needs(nn,flag) + if type(t)==types.DictType: + for nnn in t.keys(): + if tmp.has_key(nnn): tmp[nnn]=t[nnn]+tmp[nnn] + else: tmp[nnn]=t[nnn] + if not tmp.has_key(n): tmp[n]=[] + tmp[n].append(need) + return tmp + else: + errmess('append_needs: expected list or string but got :%s\n'%(`need`)) + +def get_needs(): + global outneeds,needs + res={} + for n in outneeds.keys(): + out=[] + saveout=copy.copy(outneeds[n]) + while len(outneeds[n])>0: + if not needs.has_key(outneeds[n][0]): + out.append(outneeds[n][0]) + del outneeds[n][0] + else: + flag=0 + for k in outneeds[n][1:]: + if k in needs[outneeds[n][0]]: + flag=1 + break + if flag: + outneeds[n]=outneeds[n][1:]+[outneeds[n][0]] + else: + out.append(outneeds[n][0]) + del outneeds[n][0] + if saveout and (0 not in map(lambda x,y:x==y,saveout,outneeds[n])): + print n,saveout + errmess('get_needs: no progress in sorting needs, probably circular dependence, skipping.\n') + out=out+saveout + break + saveout=copy.copy(outneeds[n]) + if out==[]: out=[n] + res[n]=out + return res diff --git a/numpy/f2py/common_rules.py b/numpy/f2py/common_rules.py new file mode 100644 index 000000000..e7b4decca --- /dev/null +++ b/numpy/f2py/common_rules.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +""" + +Build common block mechanism for f2py2e. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/05/06 10:57:33 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.19 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +import pprint +import sys,string,time,types,copy +errmess=sys.stderr.write +outmess=sys.stdout.write +show=pprint.pprint + +from auxfuncs import * +import capi_maps +import cfuncs +import func2subr +from crackfortran import rmbadname +############## + +def findcommonblocks(block,top=1): + ret = [] + if hascommon(block): + for n in block['common'].keys(): + vars={} + for v in block['common'][n]: + vars[v]=block['vars'][v] + ret.append((n,block['common'][n],vars)) + elif hasbody(block): + for b in block['body']: + ret=ret+findcommonblocks(b,0) + if top: + tret=[] + names=[] + for t in ret: + if t[0] not in names: + names.append(t[0]) + tret.append(t) + return tret + return ret + +def buildhooks(m): + ret = {'commonhooks':[],'initcommonhooks':[],'docs':['"COMMON blocks:\\n"']} + fwrap = [''] + def fadd(line,s=fwrap): s[0] = '%s\n %s'%(s[0],line) + chooks = [''] + def cadd(line,s=chooks): s[0] = '%s\n%s'%(s[0],line) + ihooks = [''] + def iadd(line,s=ihooks): s[0] = '%s\n%s'%(s[0],line) + doc = [''] + def dadd(line,s=doc): s[0] = '%s\n%s'%(s[0],line) + for (name,vnames,vars) in findcommonblocks(m): + lower_name = string.lower(name) + hnames,inames = [],[] + for n in vnames: + if isintent_hide(vars[n]): hnames.append(n) + else: inames.append(n) + if hnames: + outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n\t\t Hidden: %s\n'%(name,string.join(inames,','),string.join(hnames,','))) + else: + outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n'%(name,string.join(inames,','))) + fadd('subroutine f2pyinit%s(setupfunc)'%name) + fadd('external setupfunc') + for n in vnames: + fadd(func2subr.var2fixfortran(vars,n)) + if name=='_BLNK_': + fadd('common %s'%(string.join(vnames,','))) + else: + fadd('common /%s/ %s'%(name,string.join(vnames,','))) + fadd('call setupfunc(%s)'%(string.join(inames,','))) + fadd('end\n') + cadd('static FortranDataDef f2py_%s_def[] = {'%(name)) + idims=[] + for n in inames: + ct = capi_maps.getctype(vars[n]) + at = capi_maps.c2capi_map[ct] + dm = capi_maps.getarrdims(n,vars[n]) + if dm['dims']: idims.append('(%s)'%(dm['dims'])) + else: idims.append('') + dms=string.strip(dm['dims']) + if not dms: dms='-1' + cadd('\t{\"%s\",%s,{{%s}},%s},'%(n,dm['rank'],dms,at)) + cadd('\t{NULL}\n};') + inames1 = rmbadname(inames) + inames1_tps = string.join(map(lambda s:'char *'+s,inames1),',') + cadd('static void f2py_setup_%s(%s) {'%(name,inames1_tps)) + cadd('\tint i_f2py=0;') + for n in inames1: + cadd('\tf2py_%s_def[i_f2py++].data = %s;'%(name,n)) + cadd('}') + if '_' in lower_name: + F_FUNC='F_FUNC_US' + else: + F_FUNC='F_FUNC' + cadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void(*)(%s));'\ + %(F_FUNC,lower_name,string.upper(name), + string.join(['char*']*len(inames1),','))) + cadd('static void f2py_init_%s(void) {'%name) + cadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);'\ + %(F_FUNC,lower_name,string.upper(name),name)) + cadd('}\n') + iadd('\tPyDict_SetItemString(d, \"%s\", PyFortranObject_New(f2py_%s_def,f2py_init_%s));'%(name,name,name)) + tname = string.replace(name,'_','\\_') + dadd('\\subsection{Common block \\texttt{%s}}\n'%(tname)) + dadd('\\begin{description}') + for n in inames: + dadd('\\item[]{{}\\verb@%s@{}}'%(capi_maps.getarrdocsign(n,vars[n]))) + if hasnote(vars[n]): + note = vars[n]['note'] + if type(note) is type([]): note=string.join(note,'\n') + dadd('--- %s'%(note)) + dadd('\\end{description}') + ret['docs'].append('"\t/%s/ %s\\n"'%(name,string.join(map(lambda v,d:v+d,inames,idims),','))) + ret['commonhooks']=chooks + ret['initcommonhooks']=ihooks + ret['latexdoc']=doc[0] + if len(ret['docs'])<=1: ret['docs']='' + return ret,fwrap[0] + diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py new file mode 100755 index 000000000..2a91709bc --- /dev/null +++ b/numpy/f2py/crackfortran.py @@ -0,0 +1,2659 @@ +#!/usr/bin/env python +""" +crackfortran --- read fortran (77,90) code and extract declaration information. + Usage is explained in the comment block below. + +Copyright 1999-2004 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/09/27 07:13:49 $ +Pearu Peterson +""" +__version__ = "$Revision: 1.177 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +""" + Usage of crackfortran: + ====================== + Command line keys: -quiet,-verbose,-fix,-f77,-f90,-show,-h <pyffilename> + -m <module name for f77 routines>,--ignore-contains + Functions: crackfortran, crack2fortran + The following Fortran statements/constructions are supported + (or will be if needed): + block data,byte,call,character,common,complex,contains,data, + dimension,double complex,double precision,end,external,function, + implicit,integer,intent,interface,intrinsic, + logical,module,optional,parameter,private,public, + program,real,(sequence?),subroutine,type,use,virtual, + include,pythonmodule + Note: 'virtual' is mapped to 'dimension'. + Note: 'implicit integer (z) static (z)' is 'implicit static (z)' (this is minor bug). + Note: code after 'contains' will be ignored until its scope ends. + Note: 'common' statement is extended: dimensions are moved to variable definitions + Note: f2py directive: <commentchar>f2py<line> is read as <line> + Note: pythonmodule is introduced to represent Python module + + Usage: + `postlist=crackfortran(files,funcs)` + `postlist` contains declaration information read from the list of files `files`. + `crack2fortran(postlist)` returns a fortran code to be saved to pyf-file + + `postlist` has the following structure: + *** it is a list of dictionaries containing `blocks': + B = {'block','body','vars','parent_block'[,'name','prefix','args','result', + 'implicit','externals','interfaced','common','sortvars', + 'commonvars','note']} + B['block'] = 'interface' | 'function' | 'subroutine' | 'module' | + 'program' | 'block data' | 'type' | 'pythonmodule' + B['body'] --- list containing `subblocks' with the same structure as `blocks' + B['parent_block'] --- dictionary of a parent block: + C['body'][<index>]['parent_block'] is C + B['vars'] --- dictionary of variable definitions + B['sortvars'] --- dictionary of variable definitions sorted by dependence (independent first) + B['name'] --- name of the block (not if B['block']=='interface') + B['prefix'] --- prefix string (only if B['block']=='function') + B['args'] --- list of argument names if B['block']== 'function' | 'subroutine' + B['result'] --- name of the return value (only if B['block']=='function') + B['implicit'] --- dictionary {'a':<variable definition>,'b':...} | None + B['externals'] --- list of variables being external + B['interfaced'] --- list of variables being external and defined + B['common'] --- dictionary of common blocks (list of objects) + B['commonvars'] --- list of variables used in common blocks (dimensions are moved to variable definitions) + B['from'] --- string showing the 'parents' of the current block + B['use'] --- dictionary of modules used in current block: + {<modulename>:{['only':<0|1>],['map':{<local_name1>:<use_name1>,...}]}} + B['note'] --- list of LaTeX comments on the block + B['f2pyenhancements'] --- optional dictionary + {'threadsafe':'','fortranname':<name>, + 'callstatement':<C-expr>|<multi-line block>, + 'callprotoargument':<C-expr-list>, + 'usercode':<multi-line block>|<list of multi-line blocks>, + 'pymethoddef:<multi-line block>' + } + B['entry'] --- dictionary {entryname:argslist,..} + B['varnames'] --- list of variable names given in the order of reading the + Fortran code, useful for derived types. + *** Variable definition is a dictionary + D = B['vars'][<variable name>] = + {'typespec'[,'attrspec','kindselector','charselector','=','typename']} + D['typespec'] = 'byte' | 'character' | 'complex' | 'double complex' | + 'double precision' | 'integer' | 'logical' | 'real' | 'type' + D['attrspec'] --- list of attributes (e.g. 'dimension(<arrayspec>)', + 'external','intent(in|out|inout|hide|c|callback|cache)', + 'optional','required', etc) + K = D['kindselector'] = {['*','kind']} (only if D['typespec'] = + 'complex' | 'integer' | 'logical' | 'real' ) + C = D['charselector'] = {['*','len','kind']} + (only if D['typespec']=='character') + D['='] --- initialization expression string + D['typename'] --- name of the type if D['typespec']=='type' + D['dimension'] --- list of dimension bounds + D['intent'] --- list of intent specifications + D['depend'] --- list of variable names on which current variable depends on + D['check'] --- list of C-expressions; if C-expr returns zero, exception is raised + D['note'] --- list of LaTeX comments on the variable + *** Meaning of kind/char selectors (few examples): + D['typespec>']*K['*'] + D['typespec'](kind=K['kind']) + character*C['*'] + character(len=C['len'],kind=C['kind']) + (see also fortran type declaration statement formats below) + + Fortran 90 type declaration statement format (F77 is subset of F90) +==================================================================== + (Main source: IBM XL Fortran 5.1 Language Reference Manual) + type declaration = <typespec> [[<attrspec>]::] <entitydecl> + <typespec> = byte | + character[<charselector>] | + complex[<kindselector>] | + double complex | + double precision | + integer[<kindselector>] | + logical[<kindselector>] | + real[<kindselector>] | + type(<typename>) + <charselector> = * <charlen> | + ([len=]<len>[,[kind=]<kind>]) | + (kind=<kind>[,len=<len>]) + <kindselector> = * <intlen> | + ([kind=]<kind>) + <attrspec> = comma separated list of attributes. + Only the following attributes are used in + building up the interface: + external + (parameter --- affects '=' key) + optional + intent + Other attributes are ignored. + <intentspec> = in | out | inout + <arrayspec> = comma separated list of dimension bounds. + <entitydecl> = <name> [[*<charlen>][(<arrayspec>)] | [(<arrayspec>)]*<charlen>] + [/<init_expr>/ | =<init_expr>] [,<entitydecl>] + + In addition, the following attributes are used: check,depend,note + + TODO: + * Apply 'parameter' attribute (e.g. 'integer parameter :: i=2' 'real x(i)' + -> 'real x(2)') + The above may be solved by creating appropriate preprocessor program, for example. +""" +# +import sys,string,fileinput,re,pprint,os,copy +from auxfuncs import * + +# Global flags: +strictf77=1 # Ignore `!' comments unless line[0]=='!' +sourcecodeform='fix' # 'fix','free' +quiet=0 # Be verbose if 0 (Obsolete: not used any more) +verbose=1 # Be quiet if 0, extra verbose if > 1. +tabchar=4*' ' +pyffilename='' +f77modulename='' +skipemptyends=0 # for old F77 programs without 'program' statement +ignorecontains=1 +dolowercase=1 +debug=[] +## do_analyze = 1 + +###### global variables + +## use reload(crackfortran) to reset these variables + +groupcounter=0 +grouplist={groupcounter:[]} +neededmodule=-1 +expectbegin=1 +skipblocksuntil=-1 +usermodules=[] +f90modulevars={} +gotnextfile=1 +filepositiontext='' +currentfilename='' +skipfunctions=[] +skipfuncs=[] +onlyfuncs=[] +include_paths=[] +previous_context = None + +###### Some helper functions +def show(o,f=0):pprint.pprint(o) +errmess=sys.stderr.write +def outmess(line,flag=1): + global filepositiontext + if not verbose: return + if not quiet: + if flag:sys.stdout.write(filepositiontext) + sys.stdout.write(line) +re._MAXCACHE=50 +defaultimplicitrules={} +for c in "abcdefghopqrstuvwxyz$_": defaultimplicitrules[c]={'typespec':'real'} +for c in "ijklmn": defaultimplicitrules[c]={'typespec':'integer'} +del c +badnames={} +invbadnames={} +for n in ['int','double','float','char','short','long','void','case','while', + 'return','signed','unsigned','if','for','typedef','sizeof','union', + 'struct','static','register','new','break','do','goto','switch', + 'continue','else','inline','extern','delete','const','auto', + 'len','rank','shape','index','slen','size','_i', + 'flen','fshape', + 'string','complex_double','float_double','stdin','stderr','stdout', + 'type','default']: + badnames[n]=n+'_bn' + invbadnames[n+'_bn']=n +def rmbadname1(name): + if badnames.has_key(name): + errmess('rmbadname1: Replacing "%s" with "%s".\n'%(name,badnames[name])) + return badnames[name] + return name +def rmbadname(names): return map(rmbadname1,names) + +def undo_rmbadname1(name): + if invbadnames.has_key(name): + errmess('undo_rmbadname1: Replacing "%s" with "%s".\n'\ + %(name,invbadnames[name])) + return invbadnames[name] + return name +def undo_rmbadname(names): return map(undo_rmbadname1,names) + +def getextension(name): + i=string.rfind(name,'.') + if i==-1: return '' + if '\\' in name[i:]: return '' + if '/' in name[i:]: return '' + return name[i+1:] + +is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z',re.I).match +_has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-',re.I).search +_has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-',re.I).search +_has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-',re.I).search +_free_f90_start = re.compile(r'[^c*]\s*[^\s\d\t]',re.I).match +def is_free_format(file): + """Check if file is in free format Fortran.""" + # f90 allows both fixed and free format, assuming fixed unless + # signs of free format are detected. + result = 0 + f = open(file,'r') + line = f.readline() + n = 15 # the number of non-comment lines to scan for hints + if _has_f_header(line): + n = 0 + elif _has_f90_header(line): + n = 0 + result = 1 + while n>0 and line: + if line[0]!='!': + n -= 1 + if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-2:-1]=='&': + result = 1 + break + line = f.readline() + f.close() + return result + + +####### Read fortran (77,90) code +def readfortrancode(ffile,dowithline=show,istop=1): + """ + Read fortran codes from files and + 1) Get rid of comments, line continuations, and empty lines; lower cases. + 2) Call dowithline(line) on every line. + 3) Recursively call itself when statement \"include '<filename>'\" is met. + """ + global gotnextfile,filepositiontext,currentfilename,sourcecodeform,strictf77,\ + beginpattern,quiet,verbose,dolowercase,include_paths + if not istop: + saveglobals=gotnextfile,filepositiontext,currentfilename,sourcecodeform,strictf77,\ + beginpattern,quiet,verbose,dolowercase + if ffile==[]: return + localdolowercase = dolowercase + cont=0 + finalline='' + ll='' + commentline=re.compile(r'(?P<line>([^"]*"[^"]*"[^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!]*))!{1}(?P<rest>.*)') + includeline=re.compile(r'\s*include\s*(\'|")(?P<name>[^\'"]*)(\'|")',re.I) + cont1=re.compile(r'(?P<line>.*)&\s*\Z') + cont2=re.compile(r'(\s*&|)(?P<line>.*)') + mline_mark = re.compile(r".*?'''") + if istop: dowithline('',-1) + ll,l1='','' + spacedigits=[' ']+map(str,range(10)) + filepositiontext='' + fin=fileinput.FileInput(ffile) + while 1: + l=fin.readline() + if not l: break + if fin.isfirstline(): + filepositiontext='' + currentfilename=fin.filename() + gotnextfile=1 + l1=l + strictf77=0 + sourcecodeform='fix' + ext = os.path.splitext(currentfilename)[1] + if is_f_file(currentfilename) and \ + not (_has_f90_header(l) or _has_fix_header(l)): + strictf77=1 + elif is_free_format(currentfilename) and not _has_fix_header(l): + sourcecodeform='free' + if strictf77: beginpattern=beginpattern77 + else: beginpattern=beginpattern90 + outmess('\tReading file %s (format:%s%s)\n'\ + %(`currentfilename`,sourcecodeform, + strictf77 and ',strict' or '')) + + l=string.expandtabs(l).replace('\xa0',' ') + while not l=='': # Get rid of newline characters + if l[-1] not in "\n\r\f": break + l=l[:-1] + if not strictf77: + r=commentline.match(l) + if r: + l=r.group('line')+' ' # Strip comments starting with `!' + rl=r.group('rest') + if string.lower(rl[:4])=='f2py': # f2py directive + l = l + 4*' ' + r=commentline.match(rl[4:]) + if r: l=l+r('line') + else: l = l + rl[4:] + if string.strip(l)=='': # Skip empty line + cont=0 + continue + if sourcecodeform=='fix': + if l[0] in ['*','c','!','C','#']: + if string.lower(l[1:5])=='f2py': # f2py directive + l=' '+l[5:] + else: # Skip comment line + cont=0 + continue + elif strictf77: + if len(l)>72: l=l[:72] + if not (l[0] in spacedigits): + raise 'readfortrancode: Found non-(space,digit) char in the first column.\n\tAre you sure that this code is in fix form?\n\tline=%s'%`l` + + if (not cont or strictf77) and (len(l)>5 and not l[5]==' '): + # Continuation of a previous line + ll=ll+l[6:] + finalline='' + origfinalline='' + else: + if not strictf77: + # F90 continuation + r=cont1.match(l) + if r: l=r.group('line') # Continuation follows .. + if cont: + ll=ll+cont2.match(l).group('line') + finalline='' + origfinalline='' + else: + l=' '+l[5:] # clean up line beginning from possible digits. + if localdolowercase: finalline=string.lower(ll) + else: finalline=ll + origfinalline=ll + ll=l + cont=(r is not None) + else: + l=' '+l[5:] # clean up line beginning from possible digits. + if localdolowercase: finalline=string.lower(ll) + else: finalline=ll + origfinalline =ll + ll=l + + elif sourcecodeform=='free': + if not cont and ext=='.pyf' and mline_mark.match(l): + l = l + '\n' + while 1: + lc = fin.readline() + if not lc: + errmess('Unexpected end of file when reading multiline\n') + break + l = l + lc + if mline_mark.match(lc): + break + l = l.rstrip() + r=cont1.match(l) + if r: l=r.group('line') # Continuation follows .. + if cont: + ll=ll+cont2.match(l).group('line') + finalline='' + origfinalline='' + else: + if localdolowercase: finalline=string.lower(ll) + else: finalline=ll + origfinalline =ll + ll=l + cont=(r is not None) + else: + raise ValueError,"Flag sourcecodeform must be either 'fix' or 'free': %s"%`sourcecodeform` + filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1,currentfilename,l1) + m=includeline.match(origfinalline) + if m: + fn=m.group('name') + if os.path.isfile(fn): + readfortrancode(fn,dowithline=dowithline,istop=0) + else: + include_dirs = [os.path.dirname(currentfilename)] + include_paths + foundfile = 0 + for inc_dir in include_dirs: + fn1 = os.path.join(inc_dir,fn) + if os.path.isfile(fn1): + foundfile = 1 + readfortrancode(fn1,dowithline=dowithline,istop=0) + break + if not foundfile: + outmess('readfortrancode: could not find include file %s. Ignoring.\n'%(`fn`)) + else: + dowithline(finalline) + l1=ll + if localdolowercase: + finalline=string.lower(ll) + else: finalline=ll + origfinalline = ll + filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1,currentfilename,l1) + m=includeline.match(origfinalline) + if m: + fn=m.group('name') + fn1=os.path.join(os.path.dirname(currentfilename),fn) + if os.path.isfile(fn): + readfortrancode(fn,dowithline=dowithline,istop=0) + elif os.path.isfile(fn1): + readfortrancode(fn1,dowithline=dowithline,istop=0) + else: + outmess('readfortrancode: could not find include file %s. Ignoring.\n'%(`fn`)) + else: + dowithline(finalline) + filepositiontext='' + fin.close() + if istop: dowithline('',1) + else: + gotnextfile,filepositiontext,currentfilename,sourcecodeform,strictf77,\ + beginpattern,quiet,verbose,dolowercase=saveglobals + +########### Crack line +beforethisafter=r'\s*(?P<before>%s(?=\s*(\b(%s)\b)))'+ \ + r'\s*(?P<this>(\b(%s)\b))'+ \ + r'\s*(?P<after>%s)\s*\Z' +## +fortrantypes='character|logical|integer|real|complex|double\s*(precision\s*(complex|)|complex)|type(?=\s*\([\w\s,=(*)]*\))|byte' +typespattern=re.compile(beforethisafter%('',fortrantypes,fortrantypes,'.*'),re.I),'type' +typespattern4implicit=re.compile(beforethisafter%('',fortrantypes+'|static|automatic|undefined',fortrantypes+'|static|automatic|undefined','.*'),re.I) +# +functionpattern=re.compile(beforethisafter%('([a-z]+[\w\s(=*+-/)]*?|)','function','function','.*'),re.I),'begin' +subroutinepattern=re.compile(beforethisafter%('[a-z\s]*?','subroutine','subroutine','.*'),re.I),'begin' +#modulepattern=re.compile(beforethisafter%('[a-z\s]*?','module','module','.*'),re.I),'begin' +# +groupbegins77=r'program|block\s*data' +beginpattern77=re.compile(beforethisafter%('',groupbegins77,groupbegins77,'.*'),re.I),'begin' +groupbegins90=groupbegins77+r'|module|python\s*module|interface|type(?!\s*\()' +beginpattern90=re.compile(beforethisafter%('',groupbegins90,groupbegins90,'.*'),re.I),'begin' +groupends=r'end|endprogram|endblockdata|endmodule|endpythonmodule|endinterface' +endpattern=re.compile(beforethisafter%('',groupends,groupends,'[\w\s]*'),re.I),'end' +#endifs='end\s*(if|do|where|select|while|forall)' +endifs='(end\s*(if|do|where|select|while|forall))|(module\s*procedure)' +endifpattern=re.compile(beforethisafter%('[\w]*?',endifs,endifs,'[\w\s]*'),re.I),'endif' +# +implicitpattern=re.compile(beforethisafter%('','implicit','implicit','.*'),re.I),'implicit' +dimensionpattern=re.compile(beforethisafter%('','dimension|virtual','dimension|virtual','.*'),re.I),'dimension' +externalpattern=re.compile(beforethisafter%('','external','external','.*'),re.I),'external' +optionalpattern=re.compile(beforethisafter%('','optional','optional','.*'),re.I),'optional' +requiredpattern=re.compile(beforethisafter%('','required','required','.*'),re.I),'required' +publicpattern=re.compile(beforethisafter%('','public','public','.*'),re.I),'public' +privatepattern=re.compile(beforethisafter%('','private','private','.*'),re.I),'private' +intrisicpattern=re.compile(beforethisafter%('','intrisic','intrisic','.*'),re.I),'intrisic' +intentpattern=re.compile(beforethisafter%('','intent|depend|note|check','intent|depend|note|check','\s*\(.*?\).*'),re.I),'intent' +parameterpattern=re.compile(beforethisafter%('','parameter','parameter','\s*\(.*'),re.I),'parameter' +datapattern=re.compile(beforethisafter%('','data','data','.*'),re.I),'data' +callpattern=re.compile(beforethisafter%('','call','call','.*'),re.I),'call' +entrypattern=re.compile(beforethisafter%('','entry','entry','.*'),re.I),'entry' +callfunpattern=re.compile(beforethisafter%('','callfun','callfun','.*'),re.I),'callfun' +commonpattern=re.compile(beforethisafter%('','common','common','.*'),re.I),'common' +usepattern=re.compile(beforethisafter%('','use','use','.*'),re.I),'use' +containspattern=re.compile(beforethisafter%('','contains','contains',''),re.I),'contains' +formatpattern=re.compile(beforethisafter%('','format','format','.*'),re.I),'format' +## Non-fortran and f2py-specific statements +f2pyenhancementspattern=re.compile(beforethisafter%('','threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef','threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef','.*'),re.I|re.S),'f2pyenhancements' +multilinepattern = re.compile(r"\s*(?P<before>''')(?P<this>.*?)(?P<after>''')\s*\Z",re.S),'multiline' +## + +def _simplifyargs(argsline): + a = [] + for n in string.split(markoutercomma(argsline),'@,@'): + for r in '(),': + n = string.replace(n,r,'_') + a.append(n) + return string.join(a,',') + +crackline_re_1 = re.compile(r'\s*(?P<result>\b[a-z]+[\w]*\b)\s*[=].*',re.I) +def crackline(line,reset=0): + """ + reset=-1 --- initialize + reset=0 --- crack the line + reset=1 --- final check if mismatch of blocks occured + + Cracked data is saved in grouplist[0]. + """ + global beginpattern,groupcounter,groupname,groupcache,grouplist,gotnextfile,\ + filepositiontext,currentfilename,neededmodule,expectbegin,skipblocksuntil,\ + skipemptyends,previous_context + if ';' in line and not (f2pyenhancementspattern[0].match(line) or + multilinepattern[0].match(line)): + for l in line.split(';'): + assert reset==0,`reset` # XXX: non-zero reset values need testing + crackline(l,reset) + return + if reset<0: + groupcounter=0 + groupname={groupcounter:''} + groupcache={groupcounter:{}} + grouplist={groupcounter:[]} + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['vars']={} + groupcache[groupcounter]['block']='' + groupcache[groupcounter]['name']='' + neededmodule=-1 + skipblocksuntil=-1 + return + if reset>0: + fl=0 + if f77modulename and neededmodule==groupcounter: fl=2 + while groupcounter>fl: + outmess('crackline: groupcounter=%s groupname=%s\n'%(`groupcounter`,`groupname`)) + outmess('crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.\n') + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 + if f77modulename and neededmodule==groupcounter: + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end interface + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end module + neededmodule=-1 + return + if line=='': return + flag=0 + for pat in [dimensionpattern,externalpattern,intentpattern,optionalpattern, + requiredpattern, + parameterpattern,datapattern,publicpattern,privatepattern, + intrisicpattern, + endifpattern,endpattern, + formatpattern, + beginpattern,functionpattern,subroutinepattern, + implicitpattern,typespattern,commonpattern, + callpattern,usepattern,containspattern, + entrypattern, + f2pyenhancementspattern, + multilinepattern + ]: + m = pat[0].match(line) + if m: + break + flag=flag+1 + if not m: + re_1 = crackline_re_1 + if 0<=skipblocksuntil<=groupcounter:return + if groupcache[groupcounter].has_key('externals'): + for name in groupcache[groupcounter]['externals']: + if invbadnames.has_key(name): + name=invbadnames[name] + if groupcache[groupcounter].has_key('interfaced') and name in groupcache[groupcounter]['interfaced']: continue + m1=re.match(r'(?P<before>[^"]*)\b%s\b\s*@\(@(?P<args>[^@]*)@\)@.*\Z'%name,markouterparen(line),re.I) + if m1: + m2 = re_1.match(m1.group('before')) + a = _simplifyargs(m1.group('args')) + if m2: + line='callfun %s(%s) result (%s)'%(name,a,m2.group('result')) + else: line='callfun %s(%s)'%(name,a) + m = callfunpattern[0].match(line) + if not m: + outmess('crackline: could not resolve function call for line=%s.\n'%`line`) + return + analyzeline(m,'callfun',line) + return + if verbose>1: + previous_context = None + outmess('crackline:%d: No pattern for line\n'%(groupcounter)) + return + elif pat[1]=='end': + if 0<=skipblocksuntil<groupcounter: + groupcounter=groupcounter-1 + if skipblocksuntil<=groupcounter: return + if groupcounter<=0: + raise 'crackline: groupcounter(=%s) is nonpositive. Check the blocks.'\ + % (groupcounter) + m1 = beginpattern[0].match((line)) + if (m1) and (not m1.group('this')==groupname[groupcounter]): + raise 'crackline: End group %s does not match with previous Begin group %s\n\t%s'%(`m1.group('this')`,`groupname[groupcounter]`,filepositiontext) + if skipblocksuntil==groupcounter: + skipblocksuntil=-1 + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 + if not skipemptyends: + expectbegin=1 + elif pat[1] == 'begin': + if 0<=skipblocksuntil<=groupcounter: + groupcounter=groupcounter+1 + return + gotnextfile=0 + analyzeline(m,pat[1],line) + expectbegin=0 + elif pat[1]=='endif': + pass + elif pat[1]=='contains': + if ignorecontains: return + if 0<=skipblocksuntil<=groupcounter: return + skipblocksuntil=groupcounter + else: + if 0<=skipblocksuntil<=groupcounter:return + analyzeline(m,pat[1],line) + +def markouterparen(line): + l='';f=0 + for c in line: + if c=='(': + f=f+1 + if f==1: l=l+'@(@'; continue + elif c==')': + f=f-1 + if f==0: l=l+'@)@'; continue + l=l+c + return l +def markoutercomma(line,comma=','): + l='';f=0 + cc='' + for c in line: + if (not cc or cc==')') and c=='(': + f=f+1 + cc = ')' + elif not cc and c=='\'' and (not l or l[-1]!='\\'): + f=f+1 + cc = '\'' + elif c==cc: + f=f-1 + if f==0: + cc='' + elif c==comma and f==0: + l=l+'@'+comma+'@' + continue + l=l+c + assert not f,`f,line,l,cc` + return l +def unmarkouterparen(line): + r = string.replace(string.replace(line,'@(@','('),'@)@',')') + return r +def appenddecl(decl,decl2,force=1): + if not decl: decl={} + if not decl2: return decl + if decl is decl2: return decl + for k in decl2.keys(): + if k=='typespec': + if force or not decl.has_key(k): decl[k]=decl2[k] + elif k=='attrspec': + for l in decl2[k]: + decl=setattrspec(decl,l,force) + elif k=='kindselector': + decl=setkindselector(decl,decl2[k],force) + elif k=='charselector': + decl=setcharselector(decl,decl2[k],force) + elif k in ['=','typename']: + if force or not decl.has_key(k): decl[k]=decl2[k] + elif k=='note': + pass + elif k in ['intent','check','dimension','optional','required']: + errmess('appenddecl: "%s" not implemented.\n'%k) + else: + raise 'appenddecl: Unknown variable definition key:', k + return decl + +selectpattern=re.compile(r'\s*(?P<this>(@\(@.*?@\)@|[*][\d*]+|[*]\s*@\(@.*?@\)@|))(?P<after>.*)\Z',re.I) +nameargspattern=re.compile(r'\s*(?P<name>\b[\w$]+\b)\s*(@\(@\s*(?P<args>[\w\s,]*)\s*@\)@|)\s*(result(\s*@\(@\s*(?P<result>\b[\w$]+\b)\s*@\)@|))*\s*\Z',re.I) +callnameargspattern=re.compile(r'\s*(?P<name>\b[\w$]+\b)\s*@\(@\s*(?P<args>.*)\s*@\)@\s*\Z',re.I) +real16pattern = re.compile(r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+))[dD]((?:[-+]?\d+)?)') +real8pattern = re.compile(r'([-+]?((?:\d+(?:\.\d*)?|\d*\.\d+))[eE]((?:[-+]?\d+)?)|(\d+\.\d*))') + +_intentcallbackpattern = re.compile(r'intent\s*\(.*?\bcallback\b',re.I) +def _is_intent_callback(vdecl): + for a in vdecl.get('attrspec',[]): + if _intentcallbackpattern.match(a): + return 1 + return 0 + +def _resolvenameargspattern(line): + line = markouterparen(line) + m1=nameargspattern.match(line) + if m1: return m1.group('name'),m1.group('args'),m1.group('result') + m1=callnameargspattern.match(line) + if m1: return m1.group('name'),m1.group('args'),None + return None,[],None + +def analyzeline(m,case,line): + global groupcounter,groupname,groupcache,grouplist,filepositiontext,\ + currentfilename,f77modulename,neededinterface,neededmodule,expectbegin,\ + gotnextfile,previous_context + block=m.group('this') + if case != 'multiline': + previous_context = None + if expectbegin and case not in ['begin','call','callfun','type'] \ + and not skipemptyends and groupcounter<1: + newname=string.split(os.path.basename(currentfilename),'.')[0] + outmess('analyzeline: no group yet. Creating program group with name "%s".\n'%newname) + gotnextfile=0 + groupcounter=groupcounter+1 + groupname[groupcounter]='program' + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['vars']={} + groupcache[groupcounter]['block']='program' + groupcache[groupcounter]['name']=newname + groupcache[groupcounter]['from']='fromsky' + expectbegin=0 + if case in ['begin','call','callfun']: + # Crack line => block,name,args,result + block = block.lower() + if re.match(r'block\s*data',block,re.I): block='block data' + if re.match(r'python\s*module',block,re.I): block='python module' + name,args,result = _resolvenameargspattern(m.group('after')) + if name is None: + if block=='block data': + name = '_BLOCK_DATA_' + else: + name = '' + if block not in ['interface','block data']: + outmess('analyzeline: No name/args pattern found for line.\n') + + previous_context = (block,name,groupcounter) + if args: args=rmbadname(map(string.strip,string.split(markoutercomma(args),'@,@'))) + else: args=[] + if '' in args: + while '' in args: + args.remove('') + outmess('analyzeline: argument list is malformed (missing argument).\n') + + # end of crack line => block,name,args,result + needmodule=0 + needinterface=0 + + if case in ['call','callfun']: + needinterface=1 + if not groupcache[groupcounter].has_key('args'): return + if name not in groupcache[groupcounter]['args']: + return + for it in grouplist[groupcounter]: + if it['name']==name: return + if name in groupcache[groupcounter]['interfaced']: return + block={'call':'subroutine','callfun':'function'}[case] + if f77modulename and neededmodule==-1 and groupcounter<=1: + neededmodule=groupcounter+2 + needmodule=1 + needinterface=1 + # Create new block(s) + groupcounter=groupcounter+1 + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + if needmodule: + if verbose>1: + outmess('analyzeline: Creating module block %s\n'%`f77modulename`,0) + groupname[groupcounter]='module' + groupcache[groupcounter]['block']='python module' + groupcache[groupcounter]['name']=f77modulename + groupcache[groupcounter]['from']='' + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['interfaced']=[] + groupcache[groupcounter]['vars']={} + groupcounter=groupcounter+1 + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + if needinterface: + if verbose>1: + outmess('analyzeline: Creating additional interface block.\n',0) + groupname[groupcounter]='interface' + groupcache[groupcounter]['block']='interface' + groupcache[groupcounter]['name']='unknown_interface' + groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'],groupcache[groupcounter-1]['name']) + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['interfaced']=[] + groupcache[groupcounter]['vars']={} + groupcounter=groupcounter+1 + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + groupname[groupcounter]=block + groupcache[groupcounter]['block']=block + if not name: name='unknown_'+block + groupcache[groupcounter]['prefix']=m.group('before') + groupcache[groupcounter]['name']=rmbadname1(name) + groupcache[groupcounter]['result']=result + if groupcounter==1: + groupcache[groupcounter]['from']=currentfilename + else: + if f77modulename and groupcounter==3: + groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'],currentfilename) + else: + groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'],groupcache[groupcounter-1]['name']) + for k in groupcache[groupcounter].keys(): + if not groupcache[groupcounter][k]: del groupcache[groupcounter][k] + groupcache[groupcounter]['args']=args + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['interfaced']=[] + groupcache[groupcounter]['vars']={} + groupcache[groupcounter]['entry']={} + # end of creation + if block=='type': + groupcache[groupcounter]['varnames'] = [] + + if case in ['call','callfun']: # set parents variables + if name not in groupcache[groupcounter-2]['externals']: + groupcache[groupcounter-2]['externals'].append(name) + groupcache[groupcounter]['vars']=copy.deepcopy(groupcache[groupcounter-2]['vars']) + #try: del groupcache[groupcounter]['vars'][groupcache[groupcounter-2]['name']] + #except: pass + try: del groupcache[groupcounter]['vars'][name][groupcache[groupcounter]['vars'][name]['attrspec'].index('external')] + except: pass + if block in ['function','subroutine']: # set global attributes + try: groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name],groupcache[groupcounter-2]['vars']['']) + except: pass + if case=='callfun': # return type + if result and groupcache[groupcounter]['vars'].has_key(result): + if not name==result: + groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name],groupcache[groupcounter]['vars'][result]) + #if groupcounter>1: # name is interfaced + try: groupcache[groupcounter-2]['interfaced'].append(name) + except: pass + if block=='function': + t=typespattern[0].match(m.group('before')+' '+name) + if t: + typespec,selector,attr,edecl=cracktypespec0(t.group('this'),t.group('after')) + updatevars(typespec,selector,attr,edecl) + if case in ['call','callfun']: + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end routine + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end interface + elif case=='entry': + name,args,result=_resolvenameargspattern(m.group('after')) + if name is not None: + if args: + args=rmbadname(map(string.strip,string.split(markoutercomma(args),'@,@'))) + else: args=[] + assert result is None,`result` + groupcache[groupcounter]['entry'][name] = args + previous_context = ('entry',name,groupcounter) + elif case=='type': + typespec,selector,attr,edecl=cracktypespec0(block,m.group('after')) + last_name = updatevars(typespec,selector,attr,edecl) + if last_name is not None: + previous_context = ('variable',last_name,groupcounter) + elif case in ['dimension','intent','optional','required','external','public','private','intrisic']: + edecl=groupcache[groupcounter]['vars'] + ll=m.group('after') + i=string.find(ll,'::') + if i<0 and case=='intent': + i=string.find(markouterparen(ll),'@)@')-2 + ll=ll[:i+1]+'::'+ll[i+1:] + i=string.find(ll,'::') + if ll[i:]=='::' and groupcache[groupcounter].has_key('args'): + outmess('All arguments will have attribute %s%s\n'%(m.group('this'),ll[:i])) + ll = ll + string.join(groupcache[groupcounter]['args'],',') + if i<0:i=0;pl='' + else: pl=string.strip(ll[:i]);ll=ll[i+2:] + ch = string.split(markoutercomma(pl),'@,@') + if len(ch)>1: + pl = ch[0] + outmess('analyzeline: cannot handle multiple attributes without type specification. Ignoring %r.\n' % (','.join(ch[1:]))) + last_name = None + for e in map(string.strip,string.split(markoutercomma(ll),'@,@')): + m1=namepattern.match(e) + if not m1: + if case in ['public','private']: k='' + else: + print m.groupdict() + outmess('analyzeline: no name pattern found in %s statement for %s. Skipping.\n'%(case,`e`)) + continue + else: + k=rmbadname1(m1.group('name')) + if not edecl.has_key(k): edecl[k]={} + if case=='dimension': ap=case+m1.group('after') + if case=='intent': + ap=m.group('this')+pl + if _intentcallbackpattern.match(ap): + if k not in groupcache[groupcounter]['args']: + if groupcounter>1 and \ + string.find(groupcache[groupcounter-2]['name'], + '__user__')==-1: + outmess('analyzeline: appending intent(callback) %s'\ + ' to %s arguments\n' % (k,groupcache[groupcounter]['name'])) + groupcache[groupcounter]['args'].append(k) + else: + errmess('analyzeline: intent(callback) %s is already'\ + ' in argument list' % (k)) + if case in ['optional','required','public','external','private','intrisic']: ap=case + if edecl[k].has_key('attrspec'): edecl[k]['attrspec'].append(ap) + else: edecl[k]['attrspec']=[ap] + if case=='external': + if groupcache[groupcounter]['block']=='program': + outmess('analyzeline: ignoring program arguments\n') + continue + if k not in groupcache[groupcounter]['args']: + #outmess('analyzeline: ignoring external %s (not in arguments list)\n'%(`k`)) + continue + if not groupcache[groupcounter].has_key('externals'): + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['externals'].append(k) + last_name = k + groupcache[groupcounter]['vars']=edecl + if last_name is not None: + previous_context = ('variable',last_name,groupcounter) + elif case=='parameter': + edecl=groupcache[groupcounter]['vars'] + ll=string.strip(m.group('after'))[1:-1] + last_name = None + for e in string.split(markoutercomma(ll),'@,@'): + try: + k,initexpr=map(string.strip,string.split(e,'=')) + except: + outmess('analyzeline: could not extract name,expr in parameter statement "%s" of "%s"\n'%(e,ll));continue + params = get_parameters(edecl) + k=rmbadname1(k) + if not edecl.has_key(k): edecl[k]={} + if edecl[k].has_key('=') and (not edecl[k]['=']==initexpr): + outmess('analyzeline: Overwriting the value of parameter "%s" ("%s") with "%s".\n'%(k,edecl[k]['='],initexpr)) + t = determineexprtype(initexpr,params) + if t: + if t.get('typespec')=='real': + tt = list(initexpr) + for m in real16pattern.finditer(initexpr): + tt[m.start():m.end()] = list(\ + initexpr[m.start():m.end()].lower().replace('d', 'e')) + initexpr = "".join(tt) + elif t.get('typespec')=='complex': + initexpr = initexpr[1:].lower().replace('d','e').\ + replace(',','+1j*(') + try: + v = eval(initexpr,{},params) + except (SyntaxError,NameError),msg: + errmess('analyzeline: Failed to evaluate %r. Ignoring: %s\n'\ + % (initexpr, msg)) + continue + edecl[k]['='] = repr(v) + if edecl[k].has_key('attrspec'): + edecl[k]['attrspec'].append('parameter') + else: edecl[k]['attrspec']=['parameter'] + last_name = k + groupcache[groupcounter]['vars']=edecl + if last_name is not None: + previous_context = ('variable',last_name,groupcounter) + elif case=='implicit': + if string.lower(string.strip(m.group('after')))=='none': + groupcache[groupcounter]['implicit']=None + elif m.group('after'): + if groupcache[groupcounter].has_key('implicit'): + impl=groupcache[groupcounter]['implicit'] + else: impl={} + if impl is None: + outmess('analyzeline: Overwriting earlier "implicit none" statement.\n') + impl={} + for e in string.split(markoutercomma(m.group('after')),'@,@'): + decl={} + m1=re.match(r'\s*(?P<this>.*?)\s*(\(\s*(?P<after>[a-z-, ]+)\s*\)\s*|)\Z',e,re.I) + if not m1: + outmess('analyzeline: could not extract info of implicit statement part "%s"\n'%(e));continue + m2=typespattern4implicit.match(m1.group('this')) + if not m2: + outmess('analyzeline: could not extract types pattern of implicit statement part "%s"\n'%(e));continue + typespec,selector,attr,edecl=cracktypespec0(m2.group('this'),m2.group('after')) + kindselect,charselect,typename=cracktypespec(typespec,selector) + decl['typespec']=typespec + decl['kindselector']=kindselect + decl['charselector']=charselect + decl['typename']=typename + for k in decl.keys(): + if not decl[k]: del decl[k] + for r in string.split(markoutercomma(m1.group('after')),'@,@'): + if '-' in r: + try: begc,endc=map(string.strip,string.split(r,'-')) + except: + outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement\n'%r);continue + else: begc=endc=string.strip(r) + if not len(begc)==len(endc)==1: + outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement (2)\n'%r);continue + for o in range(ord(begc),ord(endc)+1): + impl[chr(o)]=decl + groupcache[groupcounter]['implicit']=impl + elif case=='data': + ll=[] + dl='';il='';f=0;fc=1 + for c in m.group('after'): + if c=="'": fc=not fc + if c=='/' and fc: f=f+1;continue + if f==0: dl=dl+c + elif f==1: il=il+c + elif f==2: + dl = dl.strip() + if dl.startswith(','): + dl = dl[1:].strip() + ll.append([dl,il]) + dl=c;il='';f=0 + if f==2: + dl = dl.strip() + if dl.startswith(','): + dl = dl[1:].strip() + ll.append([dl,il]) + vars={} + if groupcache[groupcounter].has_key('vars'): + vars=groupcache[groupcounter]['vars'] + last_name = None + for l in ll: + l=map(string.strip,l) + if l[0][0]==',':l[0]=l[0][1:] + if l[0][0]=='(': + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%l[0]) + continue + #if '(' in l[0]: + # #outmess('analyzeline: ignoring this data statement.\n') + # continue + i=0;j=0;llen=len(l[1]) + for v in rmbadname(map(string.strip,string.split(markoutercomma(l[0]),'@,@'))): + fc=0 + while (i<llen) and (fc or not l[1][i]==','): + if l[1][i]=="'": fc=not fc + i=i+1 + i=i+1 + #v,l[1][j:i-1]=name,initvalue + if not vars.has_key(v): + vars[v]={} + if vars[v].has_key('=') and not vars[v]['=']==l[1][j:i-1]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n'%(v,vars[v]['='],l[1][j:i-1])) + vars[v]['=']=l[1][j:i-1] + j=i + last_name = v + groupcache[groupcounter]['vars']=vars + if last_name is not None: + previous_context = ('variable',last_name,groupcounter) + elif case=='common': + line=string.strip(m.group('after')) + if not line[0]=='/':line='//'+line + cl=[] + f=0;bn='';ol='' + for c in line: + if c=='/':f=f+1;continue + if f>=3: + bn = string.strip(bn) + if not bn: bn='_BLNK_' + cl.append([bn,ol]) + f=f-2;bn='';ol='' + if f%2: bn=bn+c + else: ol=ol+c + bn = string.strip(bn) + if not bn: bn='_BLNK_' + cl.append([bn,ol]) + commonkey={} + if groupcache[groupcounter].has_key('common'): + commonkey=groupcache[groupcounter]['common'] + for c in cl: + if commonkey.has_key(c[0]): + outmess('analyzeline: previously defined common block encountered. Skipping.\n') + continue + commonkey[c[0]]=[] + for i in map(string.strip,string.split(markoutercomma(c[1]),'@,@')): + if i: commonkey[c[0]].append(i) + groupcache[groupcounter]['common']=commonkey + previous_context = ('common',bn,groupcounter) + elif case=='use': + m1=re.match(r'\A\s*(?P<name>\b[\w]+\b)\s*((,(\s*\bonly\b\s*:|(?P<notonly>))\s*(?P<list>.*))|)\s*\Z',m.group('after'),re.I) + if m1: + mm=m1.groupdict() + if not groupcache[groupcounter].has_key('use'): groupcache[groupcounter]['use']={} + name=m1.group('name') + groupcache[groupcounter]['use'][name]={} + isonly=0 + if mm.has_key('list') and mm['list'] is not None: + if mm.has_key('notonly') and mm['notonly'] is None:isonly=1 + groupcache[groupcounter]['use'][name]['only']=isonly + ll=map(string.strip,string.split(mm['list'],',')) + rl={} + for l in ll: + if '=' in l: + m2=re.match(r'\A\s*(?P<local>\b[\w]+\b)\s*=\s*>\s*(?P<use>\b[\w]+\b)\s*\Z',l,re.I) + if m2: rl[string.strip(m2.group('local'))]=string.strip(m2.group('use')) + else: + outmess('analyzeline: Not local=>use pattern found in %s\n'%`l`) + else: + rl[l]=l + groupcache[groupcounter]['use'][name]['map']=rl + else: + pass + + else: + print m.groupdict() + outmess('analyzeline: Could not crack the use statement.\n') + elif case in ['f2pyenhancements']: + if not groupcache[groupcounter].has_key ('f2pyenhancements'): + groupcache[groupcounter]['f2pyenhancements'] = {} + d = groupcache[groupcounter]['f2pyenhancements'] + if m.group('this')=='usercode' and d.has_key('usercode'): + if type(d['usercode']) is type(''): + d['usercode'] = [d['usercode']] + d['usercode'].append(m.group('after')) + else: + d[m.group('this')] = m.group('after') + elif case=='multiline': + if previous_context is None: + if verbose: + outmess('analyzeline: No context for multiline block.\n') + return + gc = groupcounter + #gc = previous_context[2] + appendmultiline(groupcache[gc], + previous_context[:2], + m.group('this')) + else: + if verbose>1: + print m.groupdict() + outmess('analyzeline: No code implemented for line.\n') + +def appendmultiline(group, context_name,ml): + if not group.has_key('f2pymultilines'): + group['f2pymultilines'] = {} + d = group['f2pymultilines'] + if not d.has_key(context_name): + d[context_name] = [] + d[context_name].append(ml) + return + +def cracktypespec0(typespec,ll): + selector=None + attr=None + if re.match(r'double\s*complex',typespec,re.I): typespec='double complex' + elif re.match(r'double\s*precision',typespec,re.I): typespec='double precision' + else: typespec=string.lower(string.strip(typespec)) + m1=selectpattern.match(markouterparen(ll)) + if not m1: + outmess('cracktypespec0: no kind/char_selector pattern found for line.\n') + return + d=m1.groupdict() + for k in d.keys(): d[k]=unmarkouterparen(d[k]) + if typespec in ['complex','integer','logical','real','character','type']: + selector=d['this'] + ll=d['after'] + i=string.find(ll,'::') + if i>=0: + attr=string.strip(ll[:i]) + ll=ll[i+2:] + return typespec,selector,attr,ll +##### +namepattern=re.compile(r'\s*(?P<name>\b[\w]+\b)\s*(?P<after>.*)\s*\Z',re.I) +kindselector=re.compile(r'\s*(\(\s*(kind\s*=)?\s*(?P<kind>.*)\s*\)|[*]\s*(?P<kind2>.*?))\s*\Z',re.I) +charselector=re.compile(r'\s*(\((?P<lenkind>.*)\)|[*]\s*(?P<charlen>.*))\s*\Z',re.I) +lenkindpattern=re.compile(r'\s*(kind\s*=\s*(?P<kind>.*?)\s*(@,@\s*len\s*=\s*(?P<len>.*)|)|(len\s*=\s*|)(?P<len2>.*?)\s*(@,@\s*(kind\s*=\s*|)(?P<kind2>.*)|))\s*\Z',re.I) +lenarraypattern=re.compile(r'\s*(@\(@\s*(?!/)\s*(?P<array>.*?)\s*@\)@\s*[*]\s*(?P<len>.*?)|([*]\s*(?P<len2>.*?)|)\s*(@\(@\s*(?!/)\s*(?P<array2>.*?)\s*@\)@|))\s*(=\s*(?P<init>.*?)|(@\(@|)/\s*(?P<init2>.*?)\s*/(@\)@|)|)\s*\Z',re.I) +def removespaces(expr): + expr=string.strip(expr) + if len(expr)<=1: return expr + expr2=expr[0] + for i in range(1,len(expr)-1): + if expr[i]==' ' and \ + ((expr[i+1] in "()[]{}= ") or (expr[i-1] in "()[]{}= ")): continue + expr2=expr2+expr[i] + expr2=expr2+expr[-1] + return expr2 +def markinnerspaces(line): + l='';f=0 + cc='\'' + cc1='"' + cb='' + for c in line: + if cb=='\\' and c in ['\\','\'','"']: + l=l+c; + cb=c + continue + if f==0 and c in ['\'','"']: cc=c; cc1={'\'':'"','"':'\''}[c] + if c==cc:f=f+1 + elif c==cc:f=f-1 + elif c==' ' and f==1: l=l+'@_@'; continue + l=l+c;cb=c + return l +def updatevars(typespec,selector,attrspec,entitydecl): + global groupcache,groupcounter + last_name = None + kindselect,charselect,typename=cracktypespec(typespec,selector) + if attrspec: + attrspec=map(string.strip,string.split(markoutercomma(attrspec),'@,@')) + l = [] + c = re.compile(r'(?P<start>[a-zA-Z]+)') + for a in attrspec: + m = c.match(a) + if m: + s = string.lower(m.group('start')) + a = s + a[len(s):] + l.append(a) + attrspec = l + el=map(string.strip,string.split(markoutercomma(entitydecl),'@,@')) + el1=[] + for e in el: + for e1 in map(string.strip,string.split(markoutercomma(removespaces(markinnerspaces(e)),comma=' '),'@ @')): + if e1: el1.append(string.replace(e1,'@_@',' ')) + for e in el1: + m=namepattern.match(e) + if not m: + outmess('updatevars: no name pattern found for entity=%s. Skipping.\n'%(`e`)) + continue + ename=rmbadname1(m.group('name')) + edecl={} + if groupcache[groupcounter]['vars'].has_key(ename): + edecl=groupcache[groupcounter]['vars'][ename].copy() + has_typespec = edecl.has_key('typespec') + if not has_typespec: + edecl['typespec']=typespec + elif typespec and (not typespec==edecl['typespec']): + outmess('updatevars: attempt to change the type of "%s" ("%s") to "%s". Ignoring.\n' % (ename,edecl['typespec'],typespec)) + if not edecl.has_key('kindselector'): + edecl['kindselector']=copy.copy(kindselect) + elif kindselect: + for k in kindselect.keys(): + if edecl['kindselector'].has_key(k) and (not kindselect[k]==edecl['kindselector'][k]): + outmess('updatevars: attempt to change the kindselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (k,ename,edecl['kindselector'][k],kindselect[k])) + else: edecl['kindselector'][k]=copy.copy(kindselect[k]) + if not edecl.has_key('charselector') and charselect: + if not has_typespec: + edecl['charselector']=charselect + else: + errmess('updatevars:%s: attempt to change empty charselector to %r. Ignoring.\n' \ + %(ename,charselect)) + elif charselect: + for k in charselect.keys(): + if edecl['charselector'].has_key(k) and (not charselect[k]==edecl['charselector'][k]): + outmess('updatevars: attempt to change the charselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (k,ename,edecl['charselector'][k],charselect[k])) + else: edecl['charselector'][k]=copy.copy(charselect[k]) + if not edecl.has_key('typename'): + edecl['typename']=typename + elif typename and (not edecl['typename']==typename): + outmess('updatevars: attempt to change the typename of "%s" ("%s") to "%s". Ignoring.\n' % (ename,edecl['typename'],typename)) + if not edecl.has_key('attrspec'): + edecl['attrspec']=copy.copy(attrspec) + elif attrspec: + for a in attrspec: + if a not in edecl['attrspec']: + edecl['attrspec'].append(a) + else: + edecl['typespec']=copy.copy(typespec) + edecl['kindselector']=copy.copy(kindselect) + edecl['charselector']=copy.copy(charselect) + edecl['typename']=typename + edecl['attrspec']=copy.copy(attrspec) + if m.group('after'): + m1=lenarraypattern.match(markouterparen(m.group('after'))) + if m1: + d1=m1.groupdict() + for lk in ['len','array','init']: + if d1[lk+'2'] is not None: d1[lk]=d1[lk+'2']; del d1[lk+'2'] + for k in d1.keys(): + if d1[k] is not None: d1[k]=unmarkouterparen(d1[k]) + else: del d1[k] + if d1.has_key('len') and d1.has_key('array'): + if d1['len']=='': + d1['len']=d1['array'] + del d1['array'] + else: + d1['array']=d1['array']+','+d1['len'] + del d1['len'] + errmess('updatevars: "%s %s" is mapped to "%s %s(%s)"\n'%(typespec,e,typespec,ename,d1['array'])) + if d1.has_key('array'): + dm = 'dimension(%s)'%d1['array'] + if not edecl.has_key('attrspec') or (not edecl['attrspec']): + edecl['attrspec']=[dm] + else: + edecl['attrspec'].append(dm) + for dm1 in edecl['attrspec']: + if dm1[:9]=='dimension' and dm1!=dm: + del edecl['attrspec'][-1] + errmess('updatevars:%s: attempt to change %r to %r. Ignoring.\n' \ + % (ename,dm1,dm)) + break + + if d1.has_key('len'): + if typespec in ['complex','integer','logical','real']: + if (not edecl.has_key('kindselector')) or (not edecl['kindselector']): + edecl['kindselector']={} + edecl['kindselector']['*']=d1['len'] + elif typespec == 'character': + if (not edecl.has_key('charselector')) or (not edecl['charselector']): edecl['charselector']={} + if edecl['charselector'].has_key('len'): del edecl['charselector']['len'] + edecl['charselector']['*']=d1['len'] + if d1.has_key('init'): + if edecl.has_key('=') and (not edecl['=']==d1['init']): + outmess('updatevars: attempt to change the init expression of "%s" ("%s") to "%s". Ignoring.\n' % (ename,edecl['='],d1['init'])) + else: + edecl['=']=d1['init'] + else: + outmess('updatevars: could not crack entity declaration "%s". Ignoring.\n'%(ename+m.group('after'))) + for k in edecl.keys(): + if not edecl[k]: del edecl[k] + groupcache[groupcounter]['vars'][ename]=edecl + if groupcache[groupcounter].has_key('varnames'): + groupcache[groupcounter]['varnames'].append(ename) + last_name = ename + return last_name + +def cracktypespec(typespec,selector): + kindselect=None + charselect=None + typename=None + if selector: + if typespec in ['complex','integer','logical','real']: + kindselect=kindselector.match(selector) + if not kindselect: + outmess('cracktypespec: no kindselector pattern found for %s\n'%(`selector`)) + return + kindselect=kindselect.groupdict() + kindselect['*']=kindselect['kind2'] + del kindselect['kind2'] + for k in kindselect.keys(): + if not kindselect[k]: del kindselect[k] + for k,i in kindselect.items(): + kindselect[k] = rmbadname1(i) + elif typespec=='character': + charselect=charselector.match(selector) + if not charselect: + outmess('cracktypespec: no charselector pattern found for %s\n'%(`selector`)) + return + charselect=charselect.groupdict() + charselect['*']=charselect['charlen'] + del charselect['charlen'] + if charselect['lenkind']: + lenkind=lenkindpattern.match(markoutercomma(charselect['lenkind'])) + lenkind=lenkind.groupdict() + for lk in ['len','kind']: + if lenkind[lk+'2']: + lenkind[lk]=lenkind[lk+'2'] + charselect[lk]=lenkind[lk] + del lenkind[lk+'2'] + del charselect['lenkind'] + for k in charselect.keys(): + if not charselect[k]: del charselect[k] + for k,i in charselect.items(): + charselect[k] = rmbadname1(i) + elif typespec=='type': + typename=re.match(r'\s*\(\s*(?P<name>\w+)\s*\)',selector,re.I) + if typename: typename=typename.group('name') + else: outmess('cracktypespec: no typename found in %s\n'%(`typespec+selector`)) + else: + outmess('cracktypespec: no selector used for %s\n'%(`selector`)) + return kindselect,charselect,typename +###### +def setattrspec(decl,attr,force=0): + if not decl: decl={} + if not attr: return decl + if not decl.has_key('attrspec'): + decl['attrspec']=[attr] + return decl + if force: decl['attrspec'].append(attr) + if attr in decl['attrspec']: return decl + if attr=='static' and 'automatic' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr=='automatic' and 'static' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr=='public' and 'private' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr=='private' and 'public' not in decl['attrspec']: + decl['attrspec'].append(attr) + else: + decl['attrspec'].append(attr) + return decl +def setkindselector(decl,sel,force=0): + if not decl: decl={} + if not sel: return decl + if not decl.has_key('kindselector'): + decl['kindselector']=sel + return decl + for k in sel.keys(): + if force or not decl['kindselector'].has_key(k): + decl['kindselector'][k]=sel[k] + return decl +def setcharselector(decl,sel,force=0): + if not decl: decl={} + if not sel: return decl + if not decl.has_key('charselector'): + decl['charselector']=sel + return decl + for k in sel.keys(): + if force or not decl['charselector'].has_key(k): + decl['charselector'][k]=sel[k] + return decl +def getblockname(block,unknown='unknown'): + if block.has_key('name'): return block['name'] + return unknown +###### post processing +def setmesstext(block): + global filepositiontext + try: filepositiontext='In: %s:%s\n'%(block['from'],block['name']) + except: pass + +def get_usedict(block): + usedict = {} + if block.has_key('parent_block'): + usedict = get_usedict(block['parent_block']) + if block.has_key('use'): + usedict.update(block['use']) + return usedict + +def get_useparameters(block, param_map=None): + global f90modulevars + if param_map is None: + param_map = {} + usedict = get_usedict(block) + if not usedict: + return param_map + for usename,mapping in usedict.items(): + usename = string.lower(usename) + if not f90modulevars.has_key(usename): + continue + mvars = f90modulevars[usename] + params = get_parameters(mvars) + if not params: + continue + # XXX: apply mapping + if mapping: + errmess('get_useparameters: mapping for %s not impl.' % (mapping)) + for k,v in params.items(): + if param_map.has_key(k): + outmess('get_useparameters: overriding parameter %s with'\ + ' value from module %s' % (`k`,`usename`)) + param_map[k] = v + return param_map + +def postcrack2(block,tab='',param_map=None): + global f90modulevars + if not f90modulevars: + return block + if type(block)==types.ListType: + ret = [] + for g in block: + g = postcrack2(g,tab=tab+'\t',param_map=param_map) + ret.append(g) + return ret + setmesstext(block) + outmess('%sBlock: %s\n'%(tab,block['name']),0) + + if param_map is None: + param_map = get_useparameters(block) + + if param_map is not None and block.has_key('vars'): + vars = block['vars'] + for n in vars.keys(): + var = vars[n] + if var.has_key('kindselector'): + kind = var['kindselector'] + if kind.has_key('kind'): + val = kind['kind'] + if param_map.has_key(val): + kind['kind'] = param_map[val] + new_body = [] + for b in block['body']: + b = postcrack2(b,tab=tab+'\t',param_map=param_map) + new_body.append(b) + block['body'] = new_body + + return block + +def postcrack(block,args=None,tab=''): + """ + TODO: + function return values + determine expression types if in argument list + """ + global usermodules,onlyfunctions + if type(block)==types.ListType: + gret=[] + uret=[] + for g in block: + setmesstext(g) + g=postcrack(g,tab=tab+'\t') + if g.has_key('name') and string.find(g['name'],'__user__')>=0: # sort user routines to appear first + uret.append(g) + else: + gret.append(g) + return uret+gret + setmesstext(block) + if (not type(block)==types.DictType) and not block.has_key('block'): + raise 'postcrack: Expected block dictionary instead of ',block + if block.has_key('name') and not block['name']=='unknown_interface': + outmess('%sBlock: %s\n'%(tab,block['name']),0) + blocktype=block['block'] + block=analyzeargs(block) + block=analyzecommon(block) + block['vars']=analyzevars(block) + block['sortvars']=sortvarnames(block['vars']) + if block.has_key('args') and block['args']: + args=block['args'] + block['body']=analyzebody(block,args,tab=tab) + + userisdefined=[] +## fromuser = [] + if block.has_key('use'): + useblock=block['use'] + for k in useblock.keys(): + if string.find(k,'__user__')>=0: + userisdefined.append(k) +## if useblock[k].has_key('map'): +## for n in useblock[k]['map'].values(): +## if n not in fromuser: fromuser.append(n) + else: useblock={} + name='' + if block.has_key('name'):name=block['name'] + if block.has_key('externals') and block['externals']:# and not userisdefined: # Build a __user__ module + interfaced=[] + if block.has_key('interfaced'): interfaced=block['interfaced'] + mvars=copy.copy(block['vars']) + if name: mname=name+'__user__routines' + else: mname='unknown__user__routines' + if mname in userisdefined: + i=1 + while '%s_%i'%(mname,i) in userisdefined: i=i+1 + mname='%s_%i'%(mname,i) + interface={'block':'interface','body':[],'vars':{},'name':name+'_user_interface'} + for e in block['externals']: +## if e in fromuser: +## outmess(' Skipping %s that is defined explicitly in another use statement\n'%(`e`)) +## continue + if e in interfaced: + edef=[] + j=-1 + for b in block['body']: + j=j+1 + if b['block']=='interface': + i=-1 + for bb in b['body']: + i=i+1 + if bb.has_key('name') and bb['name']==e: + edef=copy.copy(bb) + del b['body'][i] + break + if edef: + if not b['body']: del block['body'][j] + del interfaced[interfaced.index(e)] + break + interface['body'].append(edef) + else: + if mvars.has_key(e) and not isexternal(mvars[e]): + interface['vars'][e]=mvars[e] + if interface['vars'] or interface['body']: + block['interfaced']=interfaced + mblock={'block':'python module','body':[interface],'vars':{},'name':mname,'interfaced':block['externals']} + useblock[mname]={} + usermodules.append(mblock) + if useblock: + block['use']=useblock + return block + +def sortvarnames(vars): + indep = [] + dep = [] + for v in vars.keys(): + if vars[v].has_key('depend') and vars[v]['depend']: + dep.append(v) + #print '%s depends on %s'%(v,vars[v]['depend']) + else: indep.append(v) + n = len(dep) + i = 0 + while dep: #XXX: How to catch dependence cycles correctly? + v = dep[0] + fl = 0 + for w in dep[1:]: + if w in vars[v]['depend']: + fl = 1 + break + if fl: + dep = dep[1:]+[v] + i = i + 1 + if i>n: + errmess('sortvarnames: failed to compute dependencies because' + ' of cyclic dependencies between ' + +string.join(dep,', ')+'\n') + indep = indep + dep + break + else: + indep.append(v) + dep = dep[1:] + n = len(dep) + i = 0 + #print indep + return indep + +def analyzecommon(block): + if not hascommon(block): return block + commonvars=[] + for k in block['common'].keys(): + comvars=[] + for e in block['common'][k]: + m=re.match(r'\A\s*\b(?P<name>.*?)\b\s*(\((?P<dims>.*?)\)|)\s*\Z',e,re.I) + if m: + dims=[] + if m.group('dims'): + dims=map(string.strip,string.split(markoutercomma(m.group('dims')),'@,@')) + n=string.strip(m.group('name')) + if block['vars'].has_key(n): + if block['vars'][n].has_key('attrspec'): + block['vars'][n]['attrspec'].append('dimension(%s)'%(string.join(dims,','))) + else: + block['vars'][n]['attrspec']=['dimension(%s)'%(string.join(dims,','))] + else: + if dims: + block['vars'][n]={'attrspec':['dimension(%s)'%(string.join(dims,','))]} + else: block['vars'][n]={} + if n not in commonvars: commonvars.append(n) + else: + n=e + errmess('analyzecommon: failed to extract "<name>[(<dims>)]" from "%s" in common /%s/.\n'%(e,k)) + comvars.append(n) + block['common'][k]=comvars + if not block.has_key('commonvars'): + block['commonvars']=commonvars + else: + block['commonvars']=block['commonvars']+commonvars + return block +def analyzebody(block,args,tab=''): + global usermodules,skipfuncs,onlyfuncs,f90modulevars + setmesstext(block) + body=[] + for b in block['body']: + b['parent_block'] = block + if b['block'] in ['function','subroutine']: + if args is not None and b['name'] not in args: + continue + else: + as=b['args'] + if b['name'] in skipfuncs: + continue + if onlyfuncs and b['name'] not in onlyfuncs: + continue + else: as=args + b=postcrack(b,as,tab=tab+'\t') + if b['block']=='interface' and not b['body']: + if not b.has_key('f2pyenhancements'): + continue + if string.replace(b['block'],' ','')=='pythonmodule': + usermodules.append(b) + else: + if b['block']=='module': + f90modulevars[b['name']] = b['vars'] + body.append(b) + return body +def buildimplicitrules(block): + setmesstext(block) + implicitrules=defaultimplicitrules + attrrules={} + if block.has_key('implicit'): + if block['implicit'] is None: + implicitrules=None + if verbose>1: + outmess('buildimplicitrules: no implicit rules for routine %s.\n'%`block['name']`) + else: + for k in block['implicit'].keys(): + if block['implicit'][k].get('typespec') not in ['static','automatic']: + implicitrules[k]=block['implicit'][k] + else: + attrrules[k]=block['implicit'][k]['typespec'] + return implicitrules,attrrules + +def myeval(e,g=None,l=None): + r = eval(e,g,l) + if type(r) in [type(0),type(0.0)]: + return r + raise ValueError,'r=%r' % (r) + +getlincoef_re_1 = re.compile(r'\A\b\w+\b\Z',re.I) +def getlincoef(e,xset): # e = a*x+b ; x in xset + try: + c = int(myeval(e,{},{})) + return 0,c,None + except: pass + if getlincoef_re_1.match(e): + return 1,0,e + len_e = len(e) + for x in xset: + if len(x)>len_e: continue + re_1 = re.compile(r'(?P<before>.*?)\b'+x+r'\b(?P<after>.*)',re.I) + m = re_1.match(e) + if m: + try: + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'),0,m1.group('after')) + m1 = re_1.match(ee) + b = myeval(ee,{},{}) + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'),1,m1.group('after')) + m1 = re_1.match(ee) + a = myeval(ee,{},{}) - b + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'),0.5,m1.group('after')) + m1 = re_1.match(ee) + c = myeval(ee,{},{}) + if (a*0.5+b==c): + return a,b,x + except: pass + break + return None,None,None + +_varname_match = re.compile(r'\A[a-z]\w*\Z').match +def getarrlen(dl,args,star='*'): + edl = [] + try: edl.append(myeval(dl[0],{},{})) + except: edl.append(dl[0]) + try: edl.append(myeval(dl[1],{},{})) + except: edl.append(dl[1]) + if type(edl[0]) is type(0): + p1 = 1-edl[0] + if p1==0: d = str(dl[1]) + elif p1<0: d = '%s-%s'%(dl[1],-p1) + else: d = '%s+%s'%(dl[1],p1) + elif type(edl[1]) is type(0): + p1 = 1+edl[1] + if p1==0: d='-(%s)' % (dl[0]) + else: d='%s-(%s)' % (p1,dl[0]) + else: d = '%s-(%s)+1'%(dl[1],dl[0]) + try: return `myeval(d,{},{})`,None,None + except: pass + d1,d2=getlincoef(dl[0],args),getlincoef(dl[1],args) + if None not in [d1[0],d2[0]]: + if (d1[0],d2[0])==(0,0): + return `d2[1]-d1[1]+1`,None,None + b = d2[1] - d1[1] + 1 + d1 = (d1[0],0,d1[2]) + d2 = (d2[0],b,d2[2]) + if d1[0]==0 and d2[2] in args: + if b<0: return '%s * %s - %s'%(d2[0],d2[2],-b),d2[2],'+%s)/(%s)'%(-b,d2[0]) + elif b: return '%s * %s + %s'%(d2[0],d2[2],b),d2[2],'-%s)/(%s)'%(b,d2[0]) + else: return '%s * %s'%(d2[0],d2[2]),d2[2],')/(%s)'%(d2[0]) + if d2[0]==0 and d1[2] in args: + + if b<0: return '%s * %s - %s'%(-d1[0],d1[2],-b),d1[2],'+%s)/(%s)'%(-b,-d1[0]) + elif b: return '%s * %s + %s'%(-d1[0],d1[2],b),d1[2],'-%s)/(%s)'%(b,-d1[0]) + else: return '%s * %s'%(-d1[0],d1[2]),d1[2],')/(%s)'%(-d1[0]) + if d1[2]==d2[2] and d1[2] in args: + a = d2[0] - d1[0] + if not a: return `b`,None,None + if b<0: return '%s * %s - %s'%(a,d1[2],-b),d2[2],'+%s)/(%s)'%(-b,a) + elif b: return '%s * %s + %s'%(a,d1[2],b),d2[2],'-%s)/(%s)'%(b,a) + else: return '%s * %s'%(a,d1[2]),d2[2],')/(%s)'%(a) + if d1[0]==d2[0]==1: + c = str(d1[2]) + if c not in args: + if _varname_match(c): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c)) + c = '(%s)'%c + if b==0: d='%s-%s' % (d2[2],c) + elif b<0: d='%s-%s-%s' % (d2[2],c,-b) + else: d='%s-%s+%s' % (d2[2],c,b) + elif d1[0]==0: + c2 = str(d2[2]) + if c2 not in args: + if _varname_match(c2): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) + c2 = '(%s)'%c2 + if d2[0]==1: pass + elif d2[0]==-1: c2='-%s' %c2 + else: c2='%s*%s'%(d2[0],c2) + + if b==0: d=c2 + elif b<0: d='%s-%s' % (c2,-b) + else: d='%s+%s' % (c2,b) + elif d2[0]==0: + c1 = str(d1[2]) + if c1 not in args: + if _varname_match(c1): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) + c1 = '(%s)'%c1 + if d1[0]==1: c1='-%s'%c1 + elif d1[0]==-1: c1='+%s'%c1 + elif d1[0]<0: c1='+%s*%s'%(-d1[0],c1) + else: c1 = '-%s*%s' % (d1[0],c1) + + if b==0: d=c1 + elif b<0: d='%s-%s' % (c1,-b) + else: d='%s+%s' % (c1,b) + else: + c1 = str(d1[2]) + if c1 not in args: + if _varname_match(c1): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) + c1 = '(%s)'%c1 + if d1[0]==1: c1='-%s'%c1 + elif d1[0]==-1: c1='+%s'%c1 + elif d1[0]<0: c1='+%s*%s'%(-d1[0],c1) + else: c1 = '-%s*%s' % (d1[0],c1) + + c2 = str(d2[2]) + if c2 not in args: + if _varname_match(c2): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) + c2 = '(%s)'%c2 + if d2[0]==1: pass + elif d2[0]==-1: c2='-%s' %c2 + else: c2='%s*%s'%(d2[0],c2) + + if b==0: d='%s%s' % (c2,c1) + elif b<0: d='%s%s-%s' % (c2,c1,-b) + else: d='%s%s+%s' % (c2,c1,b) + return d,None,None + +word_pattern = re.compile(r'\b[a-z][\w$]*\b',re.I) + +def _get_depend_dict(name, vars, deps): + if vars.has_key(name): + words = vars[name].get('depend',[]) + + if vars[name].has_key('=') and not isstring(vars[name]): + for word in word_pattern.findall(vars[name]['=']): + if word not in words and vars.has_key(word): + words.append(word) + for word in words[:]: + for w in deps.get(word,[]) \ + or _get_depend_dict(word, vars, deps): + if w not in words: + words.append(w) + else: + outmess('_get_depend_dict: no dependence info for %s\n' % (`name`)) + words = [] + deps[name] = words + return words + +def _calc_depend_dict(vars): + names = vars.keys() + depend_dict = {} + for n in names: + _get_depend_dict(n, vars, depend_dict) + return depend_dict + +def get_sorted_names(vars): + """ + """ + depend_dict = _calc_depend_dict(vars) + names = [] + for name in depend_dict.keys(): + if not depend_dict[name]: + names.append(name) + del depend_dict[name] + while depend_dict: + for name, lst in depend_dict.items(): + new_lst = [n for n in lst if depend_dict.has_key(n)] + if not new_lst: + names.append(name) + del depend_dict[name] + else: + depend_dict[name] = new_lst + return [name for name in names if vars.has_key(name)] + +def _kind_func(string): + #XXX: return something sensible. + if string[0] in "'\"": + string = string[1:-1] + if real16pattern.match(string): + return 16 + elif real8pattern.match(string): + return 8 + return 'kind('+string+')' + +def _selected_int_kind_func(r): + #XXX: This should be processor dependent + m = 10**r + if m<=2**8: return 1 + if m<=2**16: return 2 + if m<=2**32: return 4 + if m<=2**64: return 8 + if m<=2**128: return 16 + return -1 + +def get_parameters(vars, global_params={}): + params = copy.copy(global_params) + g_params = copy.copy(global_params) + for name,func in [('kind',_kind_func), + ('selected_int_kind',_selected_int_kind_func), + ]: + if not g_params.has_key(name): + g_params[name] = func + param_names = [] + for n in get_sorted_names(vars): + if vars[n].has_key('attrspec') and 'parameter' in vars[n]['attrspec']: + param_names.append(n) + kind_re = re.compile(r'\bkind\s*\(\s*(?P<value>.*)\s*\)',re.I) + selected_int_kind_re = re.compile(r'\bselected_int_kind\s*\(\s*(?P<value>.*)\s*\)',re.I) + for n in param_names: + if vars[n].has_key('='): + v = vars[n]['='] + if islogical(vars[n]): + v = v.lower() + for repl in [ + ('.false.','False'), + ('.true.','True'), + #TODO: test .eq., .neq., etc replacements. + ]: + v = v.replace(*repl) + v = kind_re.sub(r'kind("\1")',v) + v = selected_int_kind_re.sub(r'selected_int_kind(\1)',v) + if isinteger(vars[n]) and not selected_int_kind_re.match(v): + v = v.split('_')[0] + if isdouble(vars[n]): + tt = list(v) + for m in real16pattern.finditer(v): + tt[m.start():m.end()] = list(\ + v[m.start():m.end()].lower().replace('d', 'e')) + v = string.join(tt,'') + if iscomplex(vars[n]): + if v[0]=='(' and v[-1]==')': + l = markoutercomma(v[1:-1]).split('@,@') + print n,params + try: + params[n] = eval(v,g_params,params) + except Exception,msg: + params[n] = v + #print params + outmess('get_parameters: got "%s" on %s\n' % (msg,`v`)) + if isstring(vars[n]) and type(params[n]) is type(0): + params[n] = chr(params[n]) + nl = string.lower(n) + if nl!=n: + params[nl] = params[n] + else: + print vars[n] + outmess('get_parameters:parameter %s does not have value?!\n'%(`n`)) + return params + +def _eval_length(length,params): + if length in ['(:)','(*)','*']: + return '(*)' + return _eval_scalar(length,params) + +_is_kind_number = re.compile('\d+_').match + +def _eval_scalar(value,params): + if _is_kind_number(value): + value = value.split('_')[0] + try: + value = str(eval(value,{},params)) + except (NameError, SyntaxError): + return value + except Exception,msg: + errmess('"%s" in evaluating %r '\ + '(available names: %s)\n' \ + % (msg,value,params.keys())) + return value + +def analyzevars(block): + global f90modulevars + setmesstext(block) + implicitrules,attrrules=buildimplicitrules(block) + vars=copy.copy(block['vars']) + if block['block']=='function' and not vars.has_key(block['name']): + vars[block['name']]={} + if block['vars'].has_key(''): + del vars[''] + if block['vars'][''].has_key('attrspec'): + gen=block['vars']['']['attrspec'] + for n in vars.keys(): + for k in ['public','private']: + if k in gen: + vars[n]=setattrspec(vars[n],k) + svars=[] + args = block['args'] + for a in args: + try: + vars[a] + svars.append(a) + except KeyError: + pass + for n in vars.keys(): + if n not in args: svars.append(n) + + params = get_parameters(vars, get_useparameters(block)) + + dep_matches = {} + name_match = re.compile(r'\w[\w\d_$]*').match + for v in vars.keys(): + m = name_match(v) + if m: + n = v[m.start():m.end()] + try: + dep_matches[n] + except KeyError: + dep_matches[n] = re.compile(r'.*\b%s\b'%(v),re.I).match + for n in svars: + if n[0] in attrrules.keys(): + vars[n]=setattrspec(vars[n],attrrules[n[0]]) + if not vars[n].has_key('typespec'): + if not(vars[n].has_key('attrspec') and 'external' in vars[n]['attrspec']): + if implicitrules: + ln0 = string.lower(n[0]) + for k in implicitrules[ln0].keys(): + if k=='typespec' and implicitrules[ln0][k]=='undefined': + continue + if not vars[n].has_key(k): + vars[n][k]=implicitrules[ln0][k] + elif k=='attrspec': + for l in implicitrules[ln0][k]: + vars[n]=setattrspec(vars[n],l) + elif n in block['args']: + outmess('analyzevars: typespec of variable %s is not defined in routine %s.\n'%(`n`,block['name'])) + + if vars[n].has_key('charselector'): + if vars[n]['charselector'].has_key('len'): + l = vars[n]['charselector']['len'] + try: + l = str(eval(l,{},params)) + except: + pass + vars[n]['charselector']['len'] = l + + if vars[n].has_key('kindselector'): + if vars[n]['kindselector'].has_key('kind'): + l = vars[n]['kindselector']['kind'] + try: + l = str(eval(l,{},params)) + except: + pass + vars[n]['kindselector']['kind'] = l + + savelindims = {} + if vars[n].has_key('attrspec'): + attr=vars[n]['attrspec'] + attr.reverse() + vars[n]['attrspec']=[] + dim,intent,depend,check,note=None,None,None,None,None + for a in attr: + if a[:9]=='dimension': dim=(string.strip(a[9:]))[1:-1] + elif a[:6]=='intent': intent=(string.strip(a[6:]))[1:-1] + elif a[:6]=='depend': depend=(string.strip(a[6:]))[1:-1] + elif a[:5]=='check': check=(string.strip(a[5:]))[1:-1] + elif a[:4]=='note': note=(string.strip(a[4:]))[1:-1] + else: vars[n]=setattrspec(vars[n],a) + if intent: + if not vars[n].has_key('intent'): vars[n]['intent']=[] + for c in map(string.strip,string.split(markoutercomma(intent),'@,@')): + if not c in vars[n]['intent']: + vars[n]['intent'].append(c) + intent=None + if note: + note=string.replace(note,'\\n\\n','\n\n') + note=string.replace(note,'\\n ','\n') + if not vars[n].has_key('note'): vars[n]['note']=[note] + else: vars[n]['note'].append(note) + note=None + if depend is not None: + if not vars[n].has_key('depend'): vars[n]['depend']=[] + for c in rmbadname(map(string.strip,string.split(markoutercomma(depend),'@,@'))): + if c not in vars[n]['depend']: + vars[n]['depend'].append(c) + depend=None + if check is not None: + if not vars[n].has_key('check'): vars[n]['check']=[] + for c in map(string.strip,string.split(markoutercomma(check),'@,@')): + if not c in vars[n]['check']: + vars[n]['check'].append(c) + check=None + if dim and not vars[n].has_key('dimension'): + vars[n]['dimension']=[] + for d in rmbadname(map(string.strip,string.split(markoutercomma(dim),'@,@'))): + star = '*' + if d==':': star=':' + if params.has_key(d): + d = str(params[d]) + for p in params.keys(): + m = re.match(r'(?P<before>.*?)\b'+p+r'\b(?P<after>.*)',d,re.I) + if m: + #outmess('analyzevars:replacing parameter %s in %s (dimension of %s) with %s\n'%(`p`,`d`,`n`,`params[p]`)) + d = m.group('before')+str(params[p])+m.group('after') + if d==star: + dl = [star] + else: + dl=string.split(markoutercomma(d,':'),'@:@') + if len(dl)==2 and '*' in dl: # e.g. dimension(5:*) + dl = ['*'] + d = '*' + if len(dl)==1 and not dl[0]==star: dl = ['1',dl[0]] + if len(dl)==2: + d,v,di = getarrlen(dl,block['vars'].keys()) + if d[:4] == '1 * ': d = d[4:] + if di and di[-4:] == '/(1)': di = di[:-4] + if v: savelindims[d] = v,di + vars[n]['dimension'].append(d) + if vars[n].has_key('dimension'): + if isintent_c(vars[n]): + shape_macro = 'shape' + else: + shape_macro = 'shape'#'fshape' + if isstringarray(vars[n]): + if vars[n].has_key('charselector'): + d = vars[n]['charselector'] + if d.has_key('*'): + d = d['*'] + errmess('analyzevars: character array "character*%s %s(%s)" is considered as "character %s(%s)"; "intent(c)" is forced.\n'\ + %(d,n, + ','.join(vars[n]['dimension']), + n,','.join(vars[n]['dimension']+[d]))) + vars[n]['dimension'].append(d) + del vars[n]['charselector'] + if not vars[n].has_key('intent'): + vars[n]['intent'] = [] + if 'c' not in vars[n]['intent']: + vars[n]['intent'].append('c') + else: + errmess("analyzevars: charselector=%r unhandled." % (d)) + if not vars[n].has_key('check') and block.has_key('args') and n in block['args']: + flag=not vars[n].has_key('depend') + if flag: vars[n]['depend']=[] + vars[n]['check']=[] + if vars[n].has_key('dimension'): + #/----< no check + #vars[n]['check'].append('rank(%s)==%s'%(n,len(vars[n]['dimension']))) + i=-1; ni=len(vars[n]['dimension']) + for d in vars[n]['dimension']: + ddeps=[] # dependecies of 'd' + ad='' + pd='' + #origd = d + if not vars.has_key(d): + if savelindims.has_key(d): + pd,ad='(',savelindims[d][1] + d = savelindims[d][0] + else: + for r in block['args']: + #for r in block['vars'].keys(): + if not vars.has_key(r): continue + if re.match(r'.*?\b'+r+r'\b',d,re.I): + ddeps.append(r) + if vars.has_key(d): + if vars[d].has_key('attrspec'): + for aa in vars[d]['attrspec']: + if aa[:6]=='depend': + ddeps=ddeps+string.split((string.strip(aa[6:]))[1:-1],',') + if vars[d].has_key('depend'): + ddeps=ddeps+vars[d]['depend'] + i=i+1 + if vars.has_key(d) and (not vars[d].has_key('depend')) \ + and (not vars[d].has_key('=')) and (d not in vars[n]['depend']) \ + and l_or(isintent_in,isintent_inout,isintent_inplace)(vars[n]): + vars[d]['depend']=[n] + if ni>1: + vars[d]['=']='%s%s(%s,%s)%s'% (pd,shape_macro,n,i,ad) + else: + vars[d]['=']='%slen(%s)%s'% (pd,n,ad) + # /---< no check + if 1 and not vars[d].has_key('check'): + if ni>1: + vars[d]['check']=['%s%s(%s,%i)%s==%s'\ + %(pd,shape_macro,n,i,ad,d)] + else: + vars[d]['check']=['%slen(%s)%s>=%s'%(pd,n,ad,d)] + if not vars[d].has_key('attrspec'): vars[d]['attrspec']=['optional'] + if ('optional' not in vars[d]['attrspec']) and\ + ('required' not in vars[d]['attrspec']): + vars[d]['attrspec'].append('optional') + elif d not in ['*',':']: + #/----< no check + #if ni>1: vars[n]['check'].append('shape(%s,%i)==%s'%(n,i,d)) + #else: vars[n]['check'].append('len(%s)>=%s'%(n,d)) + if flag: + if vars.has_key(d): + if n not in ddeps: + vars[n]['depend'].append(d) + else: + vars[n]['depend'] = vars[n]['depend'] + ddeps + elif isstring(vars[n]): + length='1' + if vars[n].has_key('charselector'): + if vars[n]['charselector'].has_key('*'): + length = _eval_length(vars[n]['charselector']['*'], + params) + vars[n]['charselector']['*']=length + elif vars[n]['charselector'].has_key('len'): + length = _eval_length(vars[n]['charselector']['len'], + params) + del vars[n]['charselector']['len'] + vars[n]['charselector']['*']=length + + if not vars[n]['check']: del vars[n]['check'] + if flag and not vars[n]['depend']: del vars[n]['depend'] + if vars[n].has_key('='): + if not vars[n].has_key('attrspec'): vars[n]['attrspec']=[] + if ('optional' not in vars[n]['attrspec']) and \ + ('required' not in vars[n]['attrspec']): + vars[n]['attrspec'].append('optional') + if not vars[n].has_key('depend'): + vars[n]['depend']=[] + for v,m in dep_matches.items(): + if m(vars[n]['=']): vars[n]['depend'].append(v) + if not vars[n]['depend']: del vars[n]['depend'] + if isscalar(vars[n]): + vars[n]['='] = _eval_scalar(vars[n]['='],params) + + for n in vars.keys(): + if n==block['name']: # n is block name + if vars[n].has_key('note'): + block['note']=vars[n]['note'] + if block['block']=='function': + if block.has_key('result') and vars.has_key(block['result']): + vars[n]=appenddecl(vars[n],vars[block['result']]) + if block.has_key('prefix'): + pr=block['prefix']; ispure=0; isrec=1 + pr1=string.replace(pr,'pure','') + ispure=(not pr==pr1) + pr=string.replace(pr1,'recursive','') + isrec=(not pr==pr1) + m=typespattern[0].match(pr) + if m: + typespec,selector,attr,edecl=cracktypespec0(m.group('this'),m.group('after')) + kindselect,charselect,typename=cracktypespec(typespec,selector) + vars[n]['typespec']=typespec + if kindselect: + if kindselect.has_key('kind'): + try: + kindselect['kind'] = eval(kindselect['kind'],{},params) + except: + pass + vars[n]['kindselector']=kindselect + if charselect: vars[n]['charselector']=charselect + if typename: vars[n]['typename']=typename + if ispure: vars[n]=setattrspec(vars[n],'pure') + if isrec: vars[n]=setattrspec(vars[n],'recursive') + else: + outmess('analyzevars: prefix (%s) were not used\n'%`block['prefix']`) + if not block['block'] in ['module','pythonmodule','python module','block data']: + if block.has_key('commonvars'): + neededvars=copy.copy(block['args']+block['commonvars']) + else: + neededvars=copy.copy(block['args']) + for n in vars.keys(): + if l_or(isintent_callback,isintent_aux)(vars[n]): + neededvars.append(n) + if block.has_key('entry'): + neededvars.extend(block['entry'].keys()) + for k in block['entry'].keys(): + for n in block['entry'][k]: + if n not in neededvars: + neededvars.append(n) + if block['block']=='function': + if block.has_key('result'): + neededvars.append(block['result']) + else: + neededvars.append(block['name']) + if block['block'] in ['subroutine','function']: + name = block['name'] + if vars.has_key(name) and vars[name].has_key('intent'): + block['intent'] = vars[name]['intent'] + if block['block'] == 'type': + neededvars.extend(vars.keys()) + for n in vars.keys(): + if n not in neededvars: + del vars[n] + return vars +analyzeargs_re_1 = re.compile(r'\A[a-z]+[\w$]*\Z',re.I) +def analyzeargs(block): + setmesstext(block) + implicitrules,attrrules=buildimplicitrules(block) + if not block.has_key('args'): block['args']=[] + args=[] + re_1 = analyzeargs_re_1 + for a in block['args']: + if not re_1.match(a): # `a` is an expression + at=determineexprtype(a,block['vars'],implicitrules) + na='e_' + for c in a: + if c not in string.lowercase+string.digits: c='_' + na=na+c + if na[-1]=='_': na=na+'e' + else: na=na+'_e' + a=na + while block['vars'].has_key(a) or a in block['args']: a=a+'r' + block['vars'][a]=at + args.append(a) + if not block['vars'].has_key(a): + block['vars'][a]={} + if block.has_key('externals') and a in block['externals']+block['interfaced']: + block['vars'][a]=setattrspec(block['vars'][a],'external') + block['args']=args + + if block.has_key('entry'): + for k,args1 in block['entry'].items(): + for a in args1: + if not block['vars'].has_key(a): + block['vars'][a]={} + + for b in block['body']: + if b['name'] in args: + if not block.has_key('externals'): block['externals']=[] + if b['name'] not in block['externals']: + block['externals'].append(b['name']) + if block.has_key('result') and not block['vars'].has_key(block['result']): + block['vars'][block['result']]={} + return block +determineexprtype_re_1 = re.compile(r'\A\(.+?[,].+?\)\Z',re.I) +determineexprtype_re_2 = re.compile(r'\A[+-]?\d+(_(P<name>[\w]+)|)\Z',re.I) +determineexprtype_re_3 = re.compile(r'\A[+-]?[\d.]+[\d+-de.]*(_(P<name>[\w]+)|)\Z',re.I) +determineexprtype_re_4 = re.compile(r'\A\(.*\)\Z',re.I) +determineexprtype_re_5 = re.compile(r'\A(?P<name>\w+)\s*\(.*?\)\s*\Z',re.I) +def _ensure_exprdict(r): + if type(r) is type(0): + return {'typespec':'integer'} + if type(r) is type(0.0): + return {'typespec':'real'} + if type(r) is type(0j): + return {'typespec':'complex'} + assert type(r) is type({}),`r` + return r + +def determineexprtype(expr,vars,rules={}): + if vars.has_key(expr): + return _ensure_exprdict(vars[expr]) + expr=string.strip(expr) + if determineexprtype_re_1.match(expr): + return {'typespec':'complex'} + m=determineexprtype_re_2.match(expr) + if m: + if m.groupdict().has_key('name') and m.group('name'): + outmess('determineexprtype: selected kind types not supported (%s)\n'%`expr`) + return {'typespec':'integer'} + m = determineexprtype_re_3.match(expr) + if m: + if m.groupdict().has_key('name') and m.group('name'): + outmess('determineexprtype: selected kind types not supported (%s)\n'%`expr`) + return {'typespec':'real'} + for op in ['+','-','*','/']: + for e in map(string.strip,string.split(markoutercomma(expr,comma=op),'@'+op+'@')): + if vars.has_key(e): + return _ensure_exprdict(vars[e]) + t={} + if determineexprtype_re_4.match(expr): # in parenthesis + t=determineexprtype(expr[1:-1],vars,rules) + else: + m = determineexprtype_re_5.match(expr) + if m: + rn=m.group('name') + t=determineexprtype(m.group('name'),vars,rules) + if t and t.has_key('attrspec'): del t['attrspec'] + if not t: + if rules.has_key(rn[0]): + return _ensure_exprdict(rules[rn[0]]) + if expr[0] in '\'"': + return {'typespec':'character','charselector':{'*':'*'}} + if not t: + outmess('determineexprtype: could not determine expressions (%s) type.\n'%(`expr`)) + return t +###### +def crack2fortrangen(block,tab='\n'): + setmesstext(block) + ret='' + if type(block) is type([]): + for g in block: + ret=ret+crack2fortrangen(g,tab) + return ret + prefix='' + name='' + args='' + blocktype=block['block'] + if blocktype=='program': return '' + al=[] + if block.has_key('name'): name=block['name'] + if block.has_key('args'): + vars = block['vars'] + al = [a for a in block['args'] if not isintent_callback(vars[a])] + if block['block']=='function' or al: + args='(%s)'%string.join(al,',') + f2pyenhancements = '' + if block.has_key('f2pyenhancements'): + for k in block['f2pyenhancements'].keys(): + f2pyenhancements = '%s%s%s %s'%(f2pyenhancements,tab+tabchar,k,block['f2pyenhancements'][k]) + intent_lst = block.get('intent',[])[:] + if blocktype=='function' and 'callback' in intent_lst: + intent_lst.remove('callback') + if intent_lst: + f2pyenhancements = '%s%sintent(%s) %s'%\ + (f2pyenhancements,tab+tabchar, + string.join(intent_lst,','),name) + use='' + if block.has_key('use'): + use=use2fortran(block['use'],tab+tabchar) + common='' + if block.has_key('common'): + common=common2fortran(block['common'],tab+tabchar) + if name=='unknown_interface': name='' + result='' + if block.has_key('result'): + result=' result (%s)'%block['result'] + if block['result'] not in al: + al.append(block['result']) + #if block.has_key('prefix'): prefix=block['prefix']+' ' + body=crack2fortrangen(block['body'],tab+tabchar) + vars=vars2fortran(block,block['vars'],al,tab+tabchar) + mess='' + if block.has_key('from'): + mess='! in %s'%block['from'] + if block.has_key('entry'): + entry_stmts = '' + for k,i in block['entry'].items(): + entry_stmts = '%s%sentry %s(%s)' \ + % (entry_stmts,tab+tabchar,k,string.join(i,',')) + body = body + entry_stmts + if blocktype=='block data' and name=='_BLOCK_DATA_': + name = '' + ret='%s%s%s %s%s%s %s%s%s%s%s%s%send %s %s'%(tab,prefix,blocktype,name,args,result,mess,f2pyenhancements,use,vars,common,body,tab,blocktype,name) + return ret +def common2fortran(common,tab=''): + ret='' + for k in common.keys(): + if k=='_BLNK_': + ret='%s%scommon %s'%(ret,tab,string.join(common[k],',')) + else: + ret='%s%scommon /%s/ %s'%(ret,tab,k,string.join(common[k],',')) + return ret +def use2fortran(use,tab=''): + ret='' + for m in use.keys(): + ret='%s%suse %s,'%(ret,tab,m) + if use[m]=={}: + if ret and ret[-1]==',': ret=ret[:-1] + continue + if use[m].has_key('only') and use[m]['only']: + ret='%s,only:'%(ret) + if use[m].has_key('map') and use[m]['map']: + c=' ' + for k in use[m]['map'].keys(): + if k==use[m]['map'][k]: + ret='%s%s%s'%(ret,c,k); c=',' + else: + ret='%s%s%s=>%s'%(ret,c,k,use[m]['map'][k]); c=',' + if ret and ret[-1]==',': ret=ret[:-1] + return ret +def true_intent_list(var): + lst = var['intent'] + ret = [] + for intent in lst: + try: + exec('c = isintent_%s(var)' % intent) + except NameError: + c = 0 + if c: + ret.append(intent) + return ret +def vars2fortran(block,vars,args,tab=''): + """ + TODO: + public sub + ... + """ + setmesstext(block) + ret='' + nout=[] + for a in args: + if block['vars'].has_key(a): nout.append(a) + if block.has_key('commonvars'): + for a in block['commonvars']: + if vars.has_key(a): + if a not in nout: nout.append(a) + else: errmess('vars2fortran: Confused?!: "%s" is not defined in vars.\n'%a) + if block.has_key('varnames'): + nout.extend(block['varnames']) + for a in vars.keys(): + if a not in nout: nout.append(a) + for a in nout: + if vars[a].has_key('depend'): + for d in vars[a]['depend']: + if vars.has_key(d) and vars[d].has_key('depend') and a in vars[d]['depend']: + errmess('vars2fortran: Warning: cross-dependence between variables "%s" and "%s"\n'%(a,d)) + if block.has_key('externals') and a in block['externals']: + if isintent_callback(vars[a]): + ret='%s%sintent(callback) %s'%(ret,tab,a) + ret='%s%sexternal %s'%(ret,tab,a) + if isoptional(vars[a]): + ret='%s%soptional %s'%(ret,tab,a) + if vars.has_key(a) and not vars[a].has_key('typespec'): + continue + cont=1 + for b in block['body']: + if a==b['name'] and b['block']=='function': cont=0;break + if cont: continue + if not vars.has_key(a): + show(vars) + outmess('vars2fortran: No definition for argument "%s".\n'%a) + continue + if a==block['name'] and not block['block']=='function': + continue + if not vars[a].has_key('typespec'): + if vars[a].has_key('attrspec') and 'external' in vars[a]['attrspec']: + if a in args: + ret='%s%sexternal %s'%(ret,tab,a) + continue + show(vars[a]) + outmess('vars2fortran: No typespec for argument "%s".\n'%a) + continue + vardef=vars[a]['typespec'] + if vardef=='type' and vars[a].has_key('typename'): + vardef='%s(%s)'%(vardef,vars[a]['typename']) + selector={} + if vars[a].has_key('kindselector'): selector=vars[a]['kindselector'] + elif vars[a].has_key('charselector'): selector=vars[a]['charselector'] + if selector.has_key('*'): + if selector['*'] in ['*',':']: + vardef='%s*(%s)'%(vardef,selector['*']) + else: + vardef='%s*%s'%(vardef,selector['*']) + else: + if selector.has_key('len'): + vardef='%s(len=%s'%(vardef,selector['len']) + if selector.has_key('kind'): + vardef='%s,kind=%s)'%(vardef,selector['kind']) + else: + vardef='%s)'%(vardef) + elif selector.has_key('kind'): + vardef='%s(kind=%s)'%(vardef,selector['kind']) + c=' ' + if vars[a].has_key('attrspec'): + attr=[] + for l in vars[a]['attrspec']: + if l not in ['external']: + attr.append(l) + if attr: + vardef='%s %s'%(vardef,string.join(attr,',')) + c=',' + if vars[a].has_key('dimension'): +# if not isintent_c(vars[a]): +# vars[a]['dimension'].reverse() + vardef='%s%sdimension(%s)'%(vardef,c,string.join(vars[a]['dimension'],',')) + c=',' + if vars[a].has_key('intent'): + lst = true_intent_list(vars[a]) + if lst: + vardef='%s%sintent(%s)'%(vardef,c,string.join(lst,',')) + c=',' + if vars[a].has_key('check'): + vardef='%s%scheck(%s)'%(vardef,c,string.join(vars[a]['check'],',')) + c=',' + if vars[a].has_key('depend'): + vardef='%s%sdepend(%s)'%(vardef,c,string.join(vars[a]['depend'],',')) + c=',' + if vars[a].has_key('='): + v = vars[a]['='] + if vars[a]['typespec'] in ['complex','double complex']: + try: + v = eval(v) + v = '(%s,%s)' % (v.real,v.imag) + except: + pass + vardef='%s :: %s=%s'%(vardef,a,v) + else: + vardef='%s :: %s'%(vardef,a) + ret='%s%s%s'%(ret,tab,vardef) + return ret +###### + +def crackfortran(files): + global usermodules + outmess('Reading fortran codes...\n',0) + readfortrancode(files,crackline) + outmess('Post-processing...\n',0) + usermodules=[] + postlist=postcrack(grouplist[0]) + outmess('Post-processing (stage 2)...\n',0) + postlist=postcrack2(postlist) + return usermodules+postlist +def crack2fortran(block): + global f2py_version + pyf=crack2fortrangen(block)+'\n' + header="""! -*- f90 -*- +! Note: the context of this file is case sensitive. +""" + footer=""" +! This file was auto-generated with f2py (version:%s). +! See http://cens.ioc.ee/projects/f2py2e/ +"""%(f2py_version) + return header+pyf+footer + +if __name__ == "__main__": + files=[] + funcs=[] + f=1;f2=0;f3=0 + showblocklist=0 + for l in sys.argv[1:]: + if l=='': pass + elif l[0]==':': + f=0 + elif l=='-quiet': + quiet=1 + verbose=0 + elif l=='-verbose': + verbose=2 + quiet=0 + elif l=='-fix': + if strictf77: + outmess('Use option -f90 before -fix if Fortran 90 code is in fix form.\n',0) + skipemptyends=1 + sourcecodeform='fix' + elif l=='-skipemptyends': + skipemptyends=1 + elif l=='--ignore-contains': + ignorecontains=1 + elif l=='-f77': + strictf77=1 + sourcecodeform='fix' + elif l=='-f90': + strictf77=0 + sourcecodeform='free' + skipemptyends=1 + elif l=='-h': + f2=1 + elif l=='-show': + showblocklist=1 + elif l=='-m': + f3=1 + elif l[0]=='-': + errmess('Unknown option %s\n'%`l`) + elif f2: + f2=0 + pyffilename=l + elif f3: + f3=0 + f77modulename=l + elif f: + try: + open(l).close() + files.append(l) + except IOError,detail: + errmess('IOError: %s\n'%str(detail)) + else: + funcs.append(l) + if not strictf77 and f77modulename and not skipemptyends: + outmess("""\ + Warning: You have specifyied module name for non Fortran 77 code + that should not need one (expect if you are scanning F90 code + for non module blocks but then you should use flag -skipemptyends + and also be sure that the files do not contain programs without program statement). +""",0) + + postlist=crackfortran(files,funcs) + if pyffilename: + outmess('Writing fortran code to file %s\n'%`pyffilename`,0) + pyf=crack2fortran(postlist) + f=open(pyffilename,'w') + f.write(pyf) + f.close() + if showblocklist: + show(postlist) diff --git a/numpy/f2py/diagnose.py b/numpy/f2py/diagnose.py new file mode 100644 index 000000000..34784b39c --- /dev/null +++ b/numpy/f2py/diagnose.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python + +import os,sys,tempfile + +def run_command(cmd): + print 'Running %r:' % (cmd) + s = os.system(cmd) + print '------' +def run(): + _path = os.getcwd() + os.chdir(tempfile.gettempdir()) + print '------' + print 'os.name=%r' % (os.name) + print '------' + print 'sys.platform=%r' % (sys.platform) + print '------' + print 'sys.version:' + print sys.version + print '------' + print 'sys.prefix:' + print sys.prefix + print '------' + print 'sys.path=%r' % (':'.join(sys.path)) + print '------' + try: + import Numeric + has_Numeric = 1 + except ImportError: + print 'Failed to import Numeric:',sys.exc_value + has_Numeric = 0 + try: + import numarray + has_numarray = 1 + except ImportError: + print 'Failed to import numarray:',sys.exc_value + has_numarray = 0 + try: + import scipy.base + has_newscipy = 1 + except ImportError: + print 'Failed to import new scipy:', sys.exc_value + has_newscipy = 0 + try: + import f2py2e + has_f2py2e = 1 + except ImportError: + print 'Failed to import f2py2e:',sys.exc_value + has_f2py2e = 0 + try: + import scipy.distutils + has_scipy_distutils = 2 + except ImportError: + try: + import scipy_distutils + has_scipy_distutils = 1 + except ImportError: + print 'Failed to import scipy_distutils:',sys.exc_value + has_scipy_distutils = 0 + if has_Numeric: + try: + print 'Found Numeric version %r in %s' % \ + (Numeric.__version__,Numeric.__file__) + except Exception,msg: + print 'error:',msg + print '------' + if has_numarray: + try: + print 'Found numarray version %r in %s' % \ + (numarray.__version__,numarray.__file__) + except Exception,msg: + print 'error:',msg + print '------' + if has_newscipy: + try: + print 'Found new scipy version %r in %s' % \ + (scipy.__version__, scipy.__file__) + except Exception,msg: + print 'error:', msg + print '------' + if has_f2py2e: + try: + print 'Found f2py2e version %r in %s' % \ + (f2py2e.__version__.version,f2py2e.__file__) + except Exception,msg: + print 'error:',msg + print '------' + if has_scipy_distutils: + try: + if has_scipy_distutils==2: + print 'Found scipy.distutils version %r in %r' % (\ + scipy.distutils.__version__, + scipy.distutils.__file__) + else: + print 'Found scipy_distutils version %r in %r' % (\ + scipy_distutils.scipy_distutils_version.scipy_distutils_version, + scipy_distutils.__file__) + print '------' + except Exception,msg: + print 'error:',msg + print '------' + try: + if has_scipy_distutils==1: + print 'Importing scipy_distutils.command.build_flib ...', + import scipy_distutils.command.build_flib as build_flib + print 'ok' + print '------' + try: + print 'Checking availability of supported Fortran compilers:' + for compiler_class in build_flib.all_compilers: + compiler_class(verbose=1).is_available() + print '------' + except Exception,msg: + print 'error:',msg + print '------' + except Exception,msg: + print 'error:',msg,'(ignore it, build_flib is obsolute for scipy.distutils 0.2.2 and up)' + print '------' + try: + if has_scipy_distutils==2: + print 'Importing scipy.distutils.fcompiler ...', + import scipy.distutils.fcompiler as fcompiler + else: + print 'Importing scipy_distutils.fcompiler ...', + import scipy_distutils.fcompiler as fcompiler + print 'ok' + print '------' + try: + print 'Checking availability of supported Fortran compilers:' + fcompiler.show_fcompilers() + print '------' + except Exception,msg: + print 'error:',msg + print '------' + except Exception,msg: + print 'error:',msg + print '------' + try: + if has_scipy_distutils==2: + print 'Importing scipy.distutils.cpuinfo ...', + from scipy.distutils.cpuinfo import cpuinfo + print 'ok' + print '------' + else: + try: + print 'Importing scipy_distutils.command.cpuinfo ...', + from scipy_distutils.command.cpuinfo import cpuinfo + print 'ok' + print '------' + except Exception,msg: + print 'error:',msg,'(ignore it)' + print 'Importing scipy_distutils.cpuinfo ...', + from scipy_distutils.cpuinfo import cpuinfo + print 'ok' + print '------' + cpu = cpuinfo() + print 'CPU information:', + for name in dir(cpuinfo): + if name[0]=='_' and name[1]!='_' and getattr(cpu,name[1:])(): + print name[1:], + print '------' + except Exception,msg: + print 'error:',msg + print '------' + os.chdir(_path) +if __name__ == "__main__": + run() diff --git a/numpy/f2py/doc/Makefile b/numpy/f2py/doc/Makefile new file mode 100644 index 000000000..2f241da0a --- /dev/null +++ b/numpy/f2py/doc/Makefile @@ -0,0 +1,76 @@ +# Makefile for compiling f2py2e documentation (dvi, ps, html) +# Pearu Peterson <pearu@ioc.ee> + +REL=4 +TOP = usersguide +LATEXSRC = bugs.tex commands.tex f2py2e.tex intro.tex notes.tex signaturefile.tex +MAINLATEX = f2py2e + +LATEX = latex +PDFLATEX = pdflatex + +COLLECTINPUT = ./collectinput.py +INSTALLDATA = install -m 644 -c + +TTH = tth +TTHFILTER = sed -e "s/{{}\\\verb@/\\\texttt{/g" | sed -e "s/@{}}/}/g" | $(TTH) -L$(MAINLATEX) -i +TTHFILTER2 = sed -e "s/{{}\\\verb@/\\\texttt{/g" | sed -e "s/@{}}/}/g" | $(TTH) -Lpython9 -i +TTHFILTER3 = sed -e "s/{{}\\\verb@/\\\texttt{/g" | sed -e "s/@{}}/}/g" | $(TTH) -Lfortranobject -i +TTHMISSING = "\ +***************************************************************\n\ +Warning: Could not find tth (a TeX to HTML translator) \n\ + or an error arised was by tth\n\ +You can download tth from http://hutchinson.belmont.ma.us/tth/ \n\ +or\n\ +use your favorite LaTeX to HTML translator on file tmp_main.tex\n\ +***************************************************************\ +" + +all: dvi ps html clean +$(MAINLATEX).dvi: $(LATEXSRC) + $(LATEX) $(MAINLATEX).tex + $(LATEX) $(MAINLATEX).tex + $(LATEX) $(MAINLATEX).tex + $(PDFLATEX) $(MAINLATEX).tex +$(TOP).dvi: $(MAINLATEX).dvi + cp -f $(MAINLATEX).dvi $(TOP).dvi + mv -f $(MAINLATEX).pdf $(TOP).pdf +$(TOP).ps: $(TOP).dvi + dvips $(TOP).dvi -o +$(TOP).html: $(LATEXSRC) + $(COLLECTINPUT) < $(MAINLATEX).tex > tmp_$(MAINLATEX).tex + @test `which $(TTH)` && cat tmp_$(MAINLATEX).tex | $(TTHFILTER) > $(TOP).html\ + || echo -e $(TTHMISSING) +dvi: $(TOP).dvi +ps: $(TOP).ps + gzip -f $(TOP).ps +html: $(TOP).html + +python9: + cp -f python9.tex f2python9-final/src/ + cd f2python9-final && mk_html.sh + cd f2python9-final && mk_ps.sh + cd f2python9-final && mk_pdf.sh +pyfobj: + $(LATEX) fortranobject.tex + $(LATEX) fortranobject.tex + $(LATEX) fortranobject.tex + @test `which $(TTH)` && cat fortranobject.tex | $(TTHFILTER3) > pyfobj.html\ + || echo -e $(TTHMISSING) + dvips fortranobject.dvi -o pyfobj.ps + gzip -f pyfobj.ps + pdflatex fortranobject.tex + mv fortranobject.pdf pyfobj.pdf + +WWWDIR=/net/cens/home/www/unsecure/projects/f2py2e/ +wwwpage: all + $(INSTALLDATA) index.html $(TOP).html $(TOP).ps.gz $(TOP).dvi $(TOP).pdf \ + Release-$(REL).x.txt ../NEWS.txt win32_notes.txt $(WWWDIR) + $(INSTALLDATA) pyfobj.{ps.gz,pdf,html} $(WWWDIR) + $(INSTALLDATA) f2python9-final/f2python9.{ps.gz,pdf,html} f2python9-final/{flow,structure,aerostructure}.jpg $(WWWDIR) +clean: + rm -f tmp_$(MAINLATEX).* $(MAINLATEX).{aux,dvi,log,toc} +distclean: + rm -f tmp_$(MAINLATEX).* $(MAINLATEX).{aux,dvi,log,toc} + rm -f $(TOP).{ps,dvi,html,pdf,ps.gz} + rm -f *~ diff --git a/numpy/f2py/doc/Release-1.x.txt b/numpy/f2py/doc/Release-1.x.txt new file mode 100644 index 000000000..46d6fbf09 --- /dev/null +++ b/numpy/f2py/doc/Release-1.x.txt @@ -0,0 +1,27 @@ + +I am pleased to announce the first public release of f2py 1.116: + +Writing Python C/API wrappers for Fortran routines can be a very +tedious task, especially if a Fortran routine takes more than 20 +arguments but only few of them are relevant for the problems that they +solve. + +The Fortran to Python Interface Generator, or FPIG for short, is a +command line tool (f2py) for generating Python C/API modules for +wrapping Fortran 77 routines, accessing common blocks from Python, and +calling Python functions from Fortran (call-backs). + +The tool can be downloaded from + + http://cens.ioc.ee/projects/f2py2e/ + +where you can find also information about f2py features and its User's +Guide. + +f2py is released under the LGPL license. + +With regards, + Pearu Peterson <pearu@ioc.ee> + +<P><A HREF="http://cens.ioc.ee/projects/f2py2e/">f2py 1.116</A> - The +Fortran to Python Interface Generator (25-Jan-00) diff --git a/numpy/f2py/doc/Release-2.x.txt b/numpy/f2py/doc/Release-2.x.txt new file mode 100644 index 000000000..807eb0ca8 --- /dev/null +++ b/numpy/f2py/doc/Release-2.x.txt @@ -0,0 +1,77 @@ + +FPIG - Fortran to Python Interface Generator + +I am pleased to announce the second public release of f2py +(version 2.264): + + http://cens.ioc.ee/projects/f2py2e/ + +f2py is a command line tool for binding Python and Fortran codes. It +scans Fortran 77/90/95 codes and generates a Python C/API module that +makes it possible to call Fortran routines from Python. No Fortran or +C expertise is required for using this tool. + +Features include: + + *** All basic Fortran types are supported: + integer[ | *1 | *2 | *4 | *8 ], logical[ | *1 | *2 | *4 | *8 ], + character[ | *(*) | *1 | *2 | *3 | ... ] + real[ | *4 | *8 | *16 ], double precision, + complex[ | *8 | *16 | *32 ] + + *** Multi-dimensional arrays of (almost) all basic types. + Dimension specifications: + <dim> | <start>:<end> | * | : + + *** Supported attributes: + intent([ in | inout | out | hide | in,out | inout,out ]) + dimension(<dimspec>) + depend([<names>]) + check([<C-booleanexpr>]) + note(<LaTeX text>) + optional, required, external + + *** Calling Fortran 77/90/95 subroutines and functions. Also + Fortran 90/95 module routines. Internal initialization of + optional arguments. + + *** Accessing COMMON blocks from Python. Accessing Fortran 90/95 + module data coming soon. + + *** Call-back functions: calling Python functions from Fortran with + very flexible hooks. + + *** In Python, arguments of the interfaced functions may be of + different type - necessary type conversations are done + internally in C level. + + *** Automatically generates documentation (__doc__,LaTeX) for + interface functions. + + *** Automatically generates signature files --- user has full + control over the interface constructions. Automatically + detects the signatures of call-back functions, solves argument + dependencies, etc. + + *** Automatically generates Makefile for compiling Fortran and C + codes and linking them to a shared module. Many compilers are + supported: gcc, Compaq Fortran, VAST/f90 Fortran, Absoft + F77/F90, MIPSpro 7 Compilers, etc. Platforms: Intel/Alpha + Linux, HP-UX, IRIX64. + + *** Complete User's Guide in various formats (html,ps,pdf,dvi). + + *** f2py users list is available for support, feedback, etc. + +More information about f2py, see + + http://cens.ioc.ee/projects/f2py2e/ + +f2py is released under the LGPL license. + +Sincerely, + Pearu Peterson <pearu@ioc.ee> + September 12, 2000 + +<P><A HREF="http://cens.ioc.ee/projects/f2py2e/">f2py 2.264</A> - The +Fortran to Python Interface Generator (12-Sep-00) diff --git a/numpy/f2py/doc/Release-3.x.txt b/numpy/f2py/doc/Release-3.x.txt new file mode 100644 index 000000000..940771015 --- /dev/null +++ b/numpy/f2py/doc/Release-3.x.txt @@ -0,0 +1,87 @@ + +F2PY - Fortran to Python Interface Generator + +I am pleased to announce the third public release of f2py +(version 2.3.321): + + http://cens.ioc.ee/projects/f2py2e/ + +f2py is a command line tool for binding Python and Fortran codes. It +scans Fortran 77/90/95 codes and generates a Python C/API module that +makes it possible to call Fortran subroutines from Python. No Fortran or +C expertise is required for using this tool. + +Features include: + + *** All basic Fortran types are supported: + integer[ | *1 | *2 | *4 | *8 ], logical[ | *1 | *2 | *4 | *8 ], + character[ | *(*) | *1 | *2 | *3 | ... ] + real[ | *4 | *8 | *16 ], double precision, + complex[ | *8 | *16 | *32 ] + + *** Multi-dimensional arrays of (almost) all basic types. + Dimension specifications: + <dim> | <start>:<end> | * | : + + *** Supported attributes and statements: + intent([ in | inout | out | hide | in,out | inout,out ]) + dimension(<dimspec>) + depend([<names>]) + check([<C-booleanexpr>]) + note(<LaTeX text>) + optional, required, external +NEW: intent(c), threadsafe, fortranname + + *** Calling Fortran 77/90/95 subroutines and functions. Also + Fortran 90/95 module subroutines are supported. Internal + initialization of optional arguments. + + *** Accessing COMMON blocks from Python. +NEW: Accessing Fortran 90/95 module data. + + *** Call-back functions: calling Python functions from Fortran with + very flexible hooks. + + *** In Python, arguments of the interfaced functions may be of + different type - necessary type conversations are done + internally in C level. + + *** Automatically generates documentation (__doc__,LaTeX) for + interfaced functions. + + *** Automatically generates signature files --- user has full + control over the interface constructions. Automatically + detects the signatures of call-back functions, solves argument + dependencies, etc. + +NEW: * Automatically generates setup_<modulename>.py for building + extension modules using tools from distutils and + fortran_support module (SciPy). + + *** Automatically generates Makefile for compiling Fortran and C + codes and linking them to a shared module. Many compilers are + supported: gcc, Compaq Fortran, VAST/f90 Fortran, Absoft + F77/F90, MIPSpro 7 Compilers, etc. Platforms: Intel/Alpha + Linux, HP-UX, IRIX64. + + *** Complete User's Guide in various formats (html,ps,pdf,dvi). + + *** f2py users list is available for support, feedback, etc. + +NEW: * Installation with distutils. + + *** And finally, many bugs are fixed. + +More information about f2py, see + + http://cens.ioc.ee/projects/f2py2e/ + +LICENSE: + f2py is released under the LGPL. + +Sincerely, + Pearu Peterson <pearu@cens.ioc.ee> + December 4, 2001 + +<P><A HREF="http://cens.ioc.ee/projects/f2py2e/">f2py 2.3.321</A> - The +Fortran to Python Interface Generator (04-Dec-01) diff --git a/numpy/f2py/doc/Release-4.x.txt b/numpy/f2py/doc/Release-4.x.txt new file mode 100644 index 000000000..ed071a0cb --- /dev/null +++ b/numpy/f2py/doc/Release-4.x.txt @@ -0,0 +1,91 @@ + +F2PY - Fortran to Python Interface Generator + +I am pleased to announce the fourth public release of f2py +(version 2.4.366): + + http://cens.ioc.ee/projects/f2py2e/ + +f2py is a command line tool for binding Python and Fortran codes. It +scans Fortran 77/90/95 codes and generates a Python C/API module that +makes it possible to call Fortran subroutines from Python. No Fortran or +C expertise is required for using this tool. + +New features: + *** Win32 support. + *** Better Python C/API generated code (-Wall is much less verbose). + +Features include: + + *** All basic Fortran types are supported: + integer[ | *1 | *2 | *4 | *8 ], logical[ | *1 | *2 | *4 | *8 ], + character[ | *(*) | *1 | *2 | *3 | ... ] + real[ | *4 | *8 | *16 ], double precision, + complex[ | *8 | *16 | *32 ] + + *** Multi-dimensional arrays of (almost) all basic types. + Dimension specifications: + <dim> | <start>:<end> | * | : + + *** Supported attributes and statements: + intent([ in | inout | out | hide | in,out | inout,out ]) + dimension(<dimspec>) + depend([<names>]) + check([<C-booleanexpr>]) + note(<LaTeX text>) + optional, required, external + intent(c), threadsafe, fortranname + + *** Calling Fortran 77/90/95 subroutines and functions. Also + Fortran 90/95 module subroutines are supported. Internal + initialization of optional arguments. + + *** Accessing COMMON blocks from Python. + Accessing Fortran 90/95 module data. + + *** Call-back functions: calling Python functions from Fortran with + very flexible hooks. + + *** In Python, arguments of the interfaced functions may be of + different type - necessary type conversations are done + internally in C level. + + *** Automatically generates documentation (__doc__,LaTeX) for + interfaced functions. + + *** Automatically generates signature files --- user has full + control over the interface constructions. Automatically + detects the signatures of call-back functions, solves argument + dependencies, etc. + + *** Automatically generates setup_<modulename>.py for building + extension modules using tools from distutils and + fortran_support module (SciPy). + + *** Automatically generates Makefile for compiling Fortran and C + codes and linking them to a shared module. Many compilers are + supported: gcc, Compaq Fortran, VAST/f90 Fortran, Absoft + F77/F90, MIPSpro 7 Compilers, etc. Platforms: Intel/Alpha + Linux, HP-UX, IRIX64. + + *** Complete User's Guide in various formats (html,ps,pdf,dvi). + + *** f2py users list is available for support, feedback, etc. + + *** Installation with distutils. + + *** And finally, many bugs are fixed. + +More information about f2py, see + + http://cens.ioc.ee/projects/f2py2e/ + +LICENSE: + f2py is released under the LGPL. + +Sincerely, + Pearu Peterson <pearu@cens.ioc.ee> + December 17, 2001 + +<P><A HREF="http://cens.ioc.ee/projects/f2py2e/">f2py 2.4.366</A> - The +Fortran to Python Interface Generator (17-Dec-01) diff --git a/numpy/f2py/doc/apps.tex b/numpy/f2py/doc/apps.tex new file mode 100644 index 000000000..513c048bd --- /dev/null +++ b/numpy/f2py/doc/apps.tex @@ -0,0 +1,71 @@ + +\section{Applications} +\label{sec:apps} + + +\subsection{Example: wrapping C library \texttt{fftw}} +\label{sec:wrapfftw} + +Here follows a simple example how to use \fpy to generate a wrapper +for C functions. Let us create a FFT code using the functions in FFTW +library. I'll assume that the library \texttt{fftw} is configured with +\texttt{-{}-enable-shared} option. + +Here is the wrapper for the typical usage of FFTW: +\begin{verbatim} +/* File: wrap_dfftw.c */ +#include <dfftw.h> + +extern void dfftw_one(fftw_complex *in,fftw_complex *out,int *n) { + fftw_plan p; + p = fftw_create_plan(*n,FFTW_FORWARD,FFTW_ESTIMATE); + fftw_one(p,in,out); + fftw_destroy_plan(p); +} +\end{verbatim} +and here follows the corresponding siganture file (created manually): +\begin{verbatim} +!%f90 +! File: fftw.f90 +module fftw + interface + subroutine dfftw_one(in,out,n) + integer n + complex*16 in(n),out(n) + intent(out) out + intent(hide) n + end subroutine dfftw_one + end interface +end module fftw +\end{verbatim} + +Now let us generate the Python C/API module with \fpy: +\begin{verbatim} +f2py fftw.f90 +\end{verbatim} +and compile it +\begin{verbatim} +gcc -shared -I/numeric/include -I`f2py -I` -L/numeric/lib -ldfftw \ + -o fftwmodule.so -DNO_APPEND_FORTRAN fftwmodule.c wrap_dfftw.c +\end{verbatim} + +In Python: +\begin{verbatim} +>>> from Numeric import * +>>> from fftw import * +>>> print dfftw_one.__doc__ +Function signature: + out = dfftw_one(in) +Required arguments: + in : input rank-1 array('D') with bounds (n) +Return objects: + out : rank-1 array('D') with bounds (n) +>>> print dfftw_one([1,2,3,4]) +[ 10.+0.j -2.+2.j -2.+0.j -2.-2.j] +>>> +\end{verbatim} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: diff --git a/numpy/f2py/doc/bugs.tex b/numpy/f2py/doc/bugs.tex new file mode 100644 index 000000000..699ecf530 --- /dev/null +++ b/numpy/f2py/doc/bugs.tex @@ -0,0 +1,109 @@ + +\section{Bugs, Plans, and Feedback} +\label{sec:bugs} + +Currently no bugs have found that I was not able to fix. I will be +happy to receive bug reports from you (so that I could fix them and +keep the first sentence of this paragraph as true as possible ;-). +Note that \fpy is developed to work properly with gcc/g77 +compilers. +\begin{description} +\item[NOTE:] Wrapping callback functions returning \texttt{COMPLEX} + may fail on some systems. Workaround: avoid it by using callback + subroutines. +\end{description} + +Here follows a list of things that I plan to implement in (near) future: +\begin{enumerate} +\item recognize file types by their extension (signatures: + \texttt{*.pyf}, Fortran 77, Fortran 90 fixed: \texttt{*.f, *.for, *.F, *.FOR}, + Fortran 90 free: \texttt{*.F90, *.f90, *.m, *.f95, *.F95}); [DONE] +\item installation using \texttt{distutils} (when it will be stable); +\item put out to the web examples of \fpy usages in real situations: + wrapping \texttt{vode}, for example; +\item implement support for \texttt{PARAMETER} statement; [DONE] +\item rewrite test-site; +\item ... +\end{enumerate} +and here are things that I plan to do in future: +\begin{enumerate} +\item implement \texttt{intent(cache)} attribute for an optional work + arrays with a feature of allocating additional memory if needed; +\item use \fpy for wrapping Fortran 90/95 codes. \fpy should scan + Fortran 90/95 codes with no problems, what needs to be done is find + out how to call a Fortran 90/95 function (from a module) from + C. Anybody there willing to test \fpy with Fortran 90/95 modules? [DONE] +\item implement support for Fortran 90/95 module data; [DONE] +\item implement support for \texttt{BLOCK DATA} blocks (if needed); +\item test/document \fpy for \texttt{CHARACTER} arrays; +\item decide whether internal transposition of multi-dimensional + arrays is reasonable (need efficient code then), even if this is + controlled by the user trough some additional keyword; need + consistent and safe policy here; +\item use \fpy for generating wrapper functions also for C programs (a + kind of SWIG, only between Python and C). For that \fpy needs a + command line switch to inform itself that C scalars are passed in by + their value, not by their reference, for instance; +\item introduce a counter that counts the number of inefficient usages + of wrapper functions (copying caused by type-casting, non-contiguous + arrays); +\item if needed, make \texttt{DATA} statement to work properly for + arrays; +\item rewrite \texttt{COMMON} wrapper; [DONE] +\item ... +\end{enumerate} +I'll appreciate any feedback that will improve \fpy (bug reports, +suggestions, etc). If you find a correct Fortran code that fails with +\fpy, try to send me a minimal version of it so that I could track +down the cause of the failure. Note also that there is no sense to +send me files that are auto-generated with \fpy (I can generate them +myself); the version of \fpy that you are using (run \texttt{\fpy\ + -v}), and the relevant fortran codes or modified signature files +should be enough information to fix the bugs. Also add some +information on compilers and linkers that you use to the bug report. + + +\section{History of \fpy} +\label{sec:history} + +\begin{enumerate} +\item I was driven to start developing a tool such as \fpy after I had + wrote several Python C/API modules for interfacing various Fortran + routines from the Netlib. This work was tedious (some of functions + had more than 20 arguments, only few of them made sense for the + problems that they solved). I realized that most of the writing + could be done automatically. +\item On 9th of July, 1999, the first lines of the tool was written. A + prototype of the tool was ready to use in only three weeks. During + this time Travis Oliphant joined to the project and shared his + valuable knowledge and experience; the call-back mechanism is his + major contribution. Then I gave the tool to public under the name + FPIG --- \emph{Fortran to Python Interface Generator}. The tool contained + only one file \texttt{f2py.py}. +\item By autumn, it was clear that a better implementation was needed + as the debugging process became very tedious. So, I reserved some + time and rewrote the tool from scratch. The most important result of + this rewriting was the code that reads real Fortran codes and + determines the signatures of the Fortran routines. The main + attention was payed in particular to this part so that the tool + could read arbitrary Fortran~77/90/95 codes. As a result, the other + side of the tools task, that is, generating Python C/API functions, + was not so great. In public, this version of the tool was called + \texttt{f2py2e} --- \emph{Fortran to Python C/API generator, the + Second Edition}. +\item So, a month before The New Year 2000, I started the third + iteration of the \fpy development. Now the main attention was to + have a good C/API module constructing code. By 21st of January, + 2000, the tool of generating wrapper functions for Fortran routines + was ready. It had many new features and was more robust than ever. +\item In 25th of January, 2000, the first public release of \fpy was + announced (version 1.116). +\item In 12th of September, 2000, the second public release of \fpy was + announced (version 2.264). It now has among other changes a support + for Fortran 90/95 module routines. +\end{enumerate} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: diff --git a/numpy/f2py/doc/collectinput.py b/numpy/f2py/doc/collectinput.py new file mode 100755 index 000000000..c2ce2bf89 --- /dev/null +++ b/numpy/f2py/doc/collectinput.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +""" +collectinput - Collects all files that are included to a main Latex document + with \input or \include commands. These commands must be + in separate lines. + +Copyright 1999 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. + +Pearu Peterson + +Usage: + collectinput <infile> <outfile> + collectinput <infile> # <outfile>=inputless_<infile> + collectinput # in and out are stdin and stdout +""" + +__version__ = "0.0" + +stdoutflag=0 +import sys,os,string,fileinput,re,commands + +try: fn=sys.argv[2] +except: + try: fn='inputless_'+sys.argv[1] + except: stdoutflag=1 +try: fi=sys.argv[1] +except: fi=() +if not stdoutflag: + sys.stdout=open(fn,'w') + +nonverb=r'[\w\s\\&=\^\*\.\{\(\)\[\?\+\$/]*(?!\\verb.)' +input=re.compile(nonverb+r'\\(input|include)\*?\s*\{?.*}?') +comment=re.compile(r'[^%]*%') + +for l in fileinput.input(fi): + l=l[:-1] + l1='' + if comment.match(l): + m=comment.match(l) + l1=l[m.end()-1:] + l=l[:m.end()-1] + m=input.match(l) + if m: + l=string.strip(l) + if l[-1]=='}': l=l[:-1] + i=m.end()-2 + sys.stderr.write('>>>>>>') + while i>-1 and (l[i] not in [' ','{']): i=i-1 + if i>-1: + fn=l[i+1:] + try: f=open(fn,'r'); flag=1; f.close() + except: + try: f=open(fn+'.tex','r'); flag=1;fn=fn+'.tex'; f.close() + except: flag=0 + if flag==0: + sys.stderr.write('Could not open a file: '+fn+'\n') + print l+l1 + continue + elif flag==1: + sys.stderr.write(fn+'\n') + print '%%%%% Begin of '+fn + print commands.getoutput(sys.argv[0]+' < '+fn) + print '%%%%% End of '+fn + else: + sys.stderr.write('Could not extract a file name from: '+l) + print l+l1 + else: + print l+l1 +sys.stdout.close() + + + diff --git a/numpy/f2py/doc/commands.tex b/numpy/f2py/doc/commands.tex new file mode 100644 index 000000000..5101a9ff5 --- /dev/null +++ b/numpy/f2py/doc/commands.tex @@ -0,0 +1,20 @@ +\usepackage{xspace} +\usepackage{verbatim} + +%%tth:\newcommand{\xspace}{ } + +\newcommand{\fpy}{\texttt{f2py}\xspace} + +\newcommand{\bs}{\symbol{`\\}} +% need bs here: +%%tth:\newcommand{\bs}{\texttt{<backslash>}} + +\newcommand{\shell}[1]{\hspace*{1em}\texttt{sh> \begin{minipage}[t]{0.8\textwidth}#1\end{minipage}}} + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: + + diff --git a/numpy/f2py/doc/ex1/arr.f b/numpy/f2py/doc/ex1/arr.f new file mode 100644 index 000000000..c4e49988f --- /dev/null +++ b/numpy/f2py/doc/ex1/arr.f @@ -0,0 +1,4 @@ + subroutine arr(l,m,n,a) + integer l,m,n + real*8 a(l,m,n) + end diff --git a/numpy/f2py/doc/ex1/bar.f b/numpy/f2py/doc/ex1/bar.f new file mode 100644 index 000000000..c723b5af1 --- /dev/null +++ b/numpy/f2py/doc/ex1/bar.f @@ -0,0 +1,4 @@ + function bar(a,b) + integer a,b,bar + bar = a + b + end diff --git a/numpy/f2py/doc/ex1/foo.f b/numpy/f2py/doc/ex1/foo.f new file mode 100644 index 000000000..cdcac4103 --- /dev/null +++ b/numpy/f2py/doc/ex1/foo.f @@ -0,0 +1,5 @@ + subroutine foo(a) + integer a +cf2py intent(in,out) :: a + a = a + 5 + end diff --git a/numpy/f2py/doc/ex1/foobar-smart.f90 b/numpy/f2py/doc/ex1/foobar-smart.f90 new file mode 100644 index 000000000..61385a685 --- /dev/null +++ b/numpy/f2py/doc/ex1/foobar-smart.f90 @@ -0,0 +1,24 @@ +!%f90 +module foobar ! in + note(This module contains two examples that are used in & + \texttt{f2py} documentation.) foobar + interface ! in :foobar + subroutine foo(a) ! in :foobar:foo.f + note(Example of a wrapper function of a Fortran subroutine.) foo + integer intent(inout),& + note(5 is added to the variable {{}\verb@a@{}} ``in place''.) :: a + end subroutine foo + function bar(a,b) result (ab) ! in :foobar:bar.f + integer :: a + integer :: b + integer :: ab + note(The first value.) a + note(The second value.) b + note(Add two values.) bar + note(The result.) ab + end function bar + end interface +end module foobar + +! This file was auto-generated with f2py (version:0.95). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/doc/ex1/foobar.f90 b/numpy/f2py/doc/ex1/foobar.f90 new file mode 100644 index 000000000..53ac5b506 --- /dev/null +++ b/numpy/f2py/doc/ex1/foobar.f90 @@ -0,0 +1,16 @@ +!%f90 +module foobar ! in + interface ! in :foobar + subroutine foo(a) ! in :foobar:foo.f + integer intent(inout) :: a + end subroutine foo + function bar(a,b) ! in :foobar:bar.f + integer :: a + integer :: b + integer :: bar + end function bar + end interface +end module foobar + +! This file was auto-generated with f2py (version:0.95). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/doc/ex1/foobarmodule.tex b/numpy/f2py/doc/ex1/foobarmodule.tex new file mode 100644 index 000000000..32411ec03 --- /dev/null +++ b/numpy/f2py/doc/ex1/foobarmodule.tex @@ -0,0 +1,36 @@ +% This file is auto-generated with f2py (version:2.266) +\section{Module \texttt{foobar}} + +This module contains two examples that are used in \texttt{f2py} documentation. + +\subsection{Wrapper function \texttt{foo}} + + +\noindent{{}\verb@foo@{}}\texttt{(a)} +--- Example of a wrapper function of a Fortran subroutine. + +\noindent Required arguments: +\begin{description} +\item[]{{}\verb@a : in/output rank-0 array(int,'i')@{}} +--- 5 is added to the variable {{}\verb@a@{}} ``in place''. +\end{description} + +\subsection{Wrapper function \texttt{bar}} + + +\noindent{{}\verb@bar = bar@{}}\texttt{(a, b)} +--- Add two values. + +\noindent Required arguments: +\begin{description} +\item[]{{}\verb@a : input int@{}} +--- The first value. +\item[]{{}\verb@b : input int@{}} +--- The second value. +\end{description} +\noindent Return objects: +\begin{description} +\item[]{{}\verb@bar : int@{}} +--- See elsewhere. +\end{description} + diff --git a/numpy/f2py/doc/ex1/runme b/numpy/f2py/doc/ex1/runme new file mode 100755 index 000000000..2aac6158e --- /dev/null +++ b/numpy/f2py/doc/ex1/runme @@ -0,0 +1,18 @@ +#!/bin/sh + +f2py2e='python ../../f2py2e.py' +PYINC=`$f2py2e -pyinc` +$f2py2e foobar-smart.pyf --short-latex --overwrite-makefile -makefile foo.f bar.f +gmake -f Makefile-foobar +#gcc -O3 -I$PYINC -I$PYINC/Numeric -shared -o foobarmodule.so foobarmodule.c foo.f bar.f +python -c ' +import foobar +print foobar.__doc__ +print foobar.bar(2,3) +from Numeric import * +a=array(3) +print a,foobar.foo(a),a +print foobar.foo.__doc__ +print foobar.bar.__doc__ +print "ok" +' diff --git a/numpy/f2py/doc/f2py2e.tex b/numpy/f2py/doc/f2py2e.tex new file mode 100644 index 000000000..6e3e9d68c --- /dev/null +++ b/numpy/f2py/doc/f2py2e.tex @@ -0,0 +1,50 @@ +\documentclass{article} +\usepackage{a4wide} + +\input commands + +\title{\fpy\\Fortran to Python Interface Generator\\{\large Second Edition}} +\author{Pearu Peterson \texttt{<pearu@ioc.ee>}} +\date{$Revision: 1.16 $\\\today} +\begin{document} +\special{html: <font size=-1>If equations does not show Greek letters or large + brackets correctly, then your browser configuration needs some + adjustment. Read the notes for <A + href=http://hutchinson.belmont.ma.us/tth/Xfonts.html>Enabling Symbol + Fonts in Netscape under X </A>. In addition, the browser must be set + to use document fonts. </font> +} + +\maketitle +\begin{abstract} + \fpy is a Python program that generates Python C/API modules for + wrapping Fortran~77/90/95 codes to Python. The user can influence the + process by modifying the signature files that \fpy generates when + scanning the Fortran codes. This document describes the syntax of + the signature files and the ways how the user can dictate the tool + to produce wrapper functions with desired Python signatures. Also + how to call the wrapper functions from Python is discussed. + + See \texttt{http://cens.ioc.ee/projects/f2py2e/} for updates of this + document and the tool. +\end{abstract} + +\tableofcontents + +\input intro +\input signaturefile +\input notes +\input options +\input bugs + +\appendix +\input ex1/foobarmodule +\input apps +\end{document} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: + + diff --git a/numpy/f2py/doc/f2python9-final/README.txt b/numpy/f2py/doc/f2python9-final/README.txt new file mode 100644 index 000000000..b907216b6 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/README.txt @@ -0,0 +1,38 @@ + +This directory contains the source of the paper + + "Fortran to Python Interface Generator with an Application + to Aerospace Engineering" + +by + Pearu Peterson <pearu@cens.ioc.ee> (the corresponding author) + Joaquim R. R. A. Martins <joaquim.martins@stanford.edu> + Juan J. Alonso <jjalonso@stanford.edu> + +for The 9th International Python Conference, March 5-8, 2001, Long Beach, California. + +The paper is provided here is in the HTML format: + + f2python9.html (size=48151 bytes) + +Note that this file includes the following JPG images + + flow.jpg (size=13266) + structure.jpg (size=17860) + aerostructure.jpg (size=72247) + +PS: +The HTML file f2python9.html is generated using TTH (http://hutchinson.belmont.ma.us/tth/) +from the LaTeX source file `python9.tex'. The source can be found in the + src/ +directory. This directory contains also the following EPS files + flow.eps + structure.eps + aerostructure.eps +and the text files + examples/{exp1.f,exp1mess.txt,exp1session.txt,foo.pyf,foom.pyf} +that are used by the LaTeX source python9.tex. + +Regards, + Pearu +January 15, 2001 diff --git a/numpy/f2py/doc/f2python9-final/aerostructure.jpg b/numpy/f2py/doc/f2python9-final/aerostructure.jpg Binary files differnew file mode 100644 index 000000000..896ad6e12 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/aerostructure.jpg diff --git a/numpy/f2py/doc/f2python9-final/flow.jpg b/numpy/f2py/doc/f2python9-final/flow.jpg Binary files differnew file mode 100644 index 000000000..cfe0f85f3 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/flow.jpg diff --git a/numpy/f2py/doc/f2python9-final/mk_html.sh b/numpy/f2py/doc/f2python9-final/mk_html.sh new file mode 100755 index 000000000..944110e93 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/mk_html.sh @@ -0,0 +1,13 @@ +#!/bin/sh +cd src + +test -f aerostructure.eps || convert ../aerostructure.jpg aerostructure.eps +test -f flow.eps || convert ../flow.jpg flow.eps +test -f structure.eps || convert ../structure.jpg structure.eps + +latex python9.tex +latex python9.tex +latex python9.tex + +test `which tth` && cat python9.tex | sed -e "s/{{}\\\verb@/\\\texttt{/g" | sed -e "s/@{}}/}/g" | tth -Lpython9 -i > ../f2python9.html +cd .. diff --git a/numpy/f2py/doc/f2python9-final/mk_pdf.sh b/numpy/f2py/doc/f2python9-final/mk_pdf.sh new file mode 100755 index 000000000..b773028b7 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/mk_pdf.sh @@ -0,0 +1,13 @@ +#!/bin/sh +cd src + +test -f aerostructure.pdf || convert ../aerostructure.jpg aerostructure.pdf +test -f flow.pdf || convert ../flow.jpg flow.pdf +test -f structure.pdf || convert ../structure.jpg structure.pdf + +cat python9.tex | sed -e "s/eps,/pdf,/g" > python9pdf.tex +pdflatex python9pdf.tex +pdflatex python9pdf.tex +pdflatex python9pdf.tex + +mv python9pdf.pdf ../f2python9.pdf
\ No newline at end of file diff --git a/numpy/f2py/doc/f2python9-final/mk_ps.sh b/numpy/f2py/doc/f2python9-final/mk_ps.sh new file mode 100755 index 000000000..4b0863fcd --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/mk_ps.sh @@ -0,0 +1,14 @@ +#!/bin/sh +cd src + +test -f aerostructure.eps || convert ../aerostructure.jpg aerostructure.eps +test -f flow.eps || convert ../flow.jpg flow.eps +test -f structure.eps || convert ../structure.jpg structure.eps + +latex python9.tex +latex python9.tex +latex python9.tex + +dvips python9.dvi -o ../f2python9.ps +cd .. +gzip -f f2python9.ps diff --git a/numpy/f2py/doc/f2python9-final/src/examples/exp1.f b/numpy/f2py/doc/f2python9-final/src/examples/exp1.f new file mode 100644 index 000000000..36bee50b0 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/src/examples/exp1.f @@ -0,0 +1,26 @@ + subroutine exp1(l,u,n) +C Input: n is number of iterations +C Output: l,u are such that +C l(1)/l(2) < exp(1) < u(1)/u(2) +C +Cf2py integer*4 :: n = 1 +Cf2py intent(out) l,u + integer*4 n,i + real*8 l(2),u(2),t,t1,t2,t3,t4 + l(2) = 1 + l(1) = 0 + u(2) = 0 + u(1) = 1 + do 10 i=0,n + t1 = 4 + 32*(1+i)*i + t2 = 11 + (40+32*i)*i + t3 = 3 + (24+32*i)*i + t4 = 8 + 32*(1+i)*i + t = u(1) + u(1) = l(1)*t1 + t*t2 + l(1) = l(1)*t3 + t*t4 + t = u(2) + u(2) = l(2)*t1 + t*t2 + l(2) = l(2)*t3 + t*t4 + 10 continue + end diff --git a/numpy/f2py/doc/f2python9-final/src/examples/exp1mess.txt b/numpy/f2py/doc/f2python9-final/src/examples/exp1mess.txt new file mode 100644 index 000000000..ae1545718 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/src/examples/exp1mess.txt @@ -0,0 +1,17 @@ +Reading fortran codes... + Reading file 'exp1.f' +Post-processing... + Block: foo + Block: exp1 +Creating 'Makefile-foo'... + Linker: ld ('GNU ld' 2.9.5) + Fortran compiler: f77 ('g77 2.x.x' 2.95.2) + C compiler: cc ('gcc 2.x.x' 2.95.2) +Building modules... + Building module "foo"... + Constructing wrapper function "exp1"... + l,u = exp1([n]) + Wrote C/API module "foo" to file "foomodule.c" + Documentation is saved to file "foomodule.tex" +Run GNU make to build shared modules: + gmake -f Makefile-<modulename> [test] diff --git a/numpy/f2py/doc/f2python9-final/src/examples/exp1session.txt b/numpy/f2py/doc/f2python9-final/src/examples/exp1session.txt new file mode 100644 index 000000000..9bec9198e --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/src/examples/exp1session.txt @@ -0,0 +1,20 @@ +>>> import foo,Numeric +>>> print foo.exp1.__doc__ +exp1 - Function signature: + l,u = exp1([n]) +Optional arguments: + n := 1 input int +Return objects: + l : rank-1 array('d') with bounds (2) + u : rank-1 array('d') with bounds (2) + +>>> l,u = foo.exp1() +>>> print l,u +[ 1264. 465.] [ 1457. 536.] +>>> print l[0]/l[1], u[0]/u[1]-l[0]/l[1] +2.71827956989 2.25856657199e-06 +>>> l,u = foo.exp1(2) +>>> print l,u +[ 517656. 190435.] [ 566827. 208524.] +>>> print l[0]/l[1], u[0]/u[1]-l[0]/l[1] +2.71828182845 1.36437527942e-11
\ No newline at end of file diff --git a/numpy/f2py/doc/f2python9-final/src/examples/foo.pyf b/numpy/f2py/doc/f2python9-final/src/examples/foo.pyf new file mode 100644 index 000000000..516bb292f --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/src/examples/foo.pyf @@ -0,0 +1,13 @@ +!%f90 -*- f90 -*- +python module foo + interface + subroutine exp1(l,u,n) + real*8 dimension(2) :: l + real*8 dimension(2) :: u + integer*4 :: n + end subroutine exp1 + end interface +end python module foo +! This file was auto-generated with f2py +! (version:2.298). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/doc/f2python9-final/src/examples/foom.pyf b/numpy/f2py/doc/f2python9-final/src/examples/foom.pyf new file mode 100644 index 000000000..6392ebc95 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/src/examples/foom.pyf @@ -0,0 +1,14 @@ +!%f90 -*- f90 -*- +python module foo + interface + subroutine exp1(l,u,n) + real*8 dimension(2) :: l + real*8 dimension(2) :: u + intent(out) l,u + integer*4 optional :: n = 1 + end subroutine exp1 + end interface +end python module foo +! This file was auto-generated with f2py +! (version:2.298) and modified by pearu. +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/doc/f2python9-final/structure.jpg b/numpy/f2py/doc/f2python9-final/structure.jpg Binary files differnew file mode 100644 index 000000000..9aa691339 --- /dev/null +++ b/numpy/f2py/doc/f2python9-final/structure.jpg diff --git a/numpy/f2py/doc/fortranobject.tex b/numpy/f2py/doc/fortranobject.tex new file mode 100644 index 000000000..dbb244cdd --- /dev/null +++ b/numpy/f2py/doc/fortranobject.tex @@ -0,0 +1,574 @@ +\documentclass{article} + +\headsep=0pt +\topmargin=0pt +\headheight=0pt +\oddsidemargin=0pt +\textwidth=6.5in +\textheight=9in + +\usepackage{xspace} +\usepackage{verbatim} +\newcommand{\fpy}{\texttt{f2py}\xspace} +\newcommand{\bs}{\symbol{`\\}} +\newcommand{\email}[1]{\special{html:<A href="mailto:#1">}\texttt{<#1>}\special{html:</A>}} +\title{\texttt{PyFortranObject} --- example usages} +\author{ +\large Pearu Peterson\\ +\small \email{pearu@cens.ioc.ee} +} + +\begin{document} + +\maketitle + +\special{html: Other formats of this document: +<A href=pyfobj.ps.gz>Gzipped PS</A>, +<A href=pyfobj.pdf>PDF</A> +} + +\tableofcontents + +\section{Introduction} +\label{sec:intro} + +Fortran language defines the following concepts that we would like to +access from Python: functions, subroutines, data in \texttt{COMMON} blocks, +F90 module functions and subroutines, F90 module data (both static and +allocatable arrays). + +In the following we shall assume that we know the signatures (full +specifications of routine arguments and variables) of these concepts +from their Fortran source codes. Now, in order to call or use them +from C, one needs to have pointers to the corresponding objects. The +pointers to Fortran 77 objects (routines, data in \texttt{COMMON} +blocks) are readily available to C codes (there are various sources +available about mixing Fortran 77 and C codes). On the other hand, F90 +module specifications are highly compiler dependent and sometimes it +is not even possible to access F90 module objects from C (at least, +not directly, see remark about MIPSPro 7 Compilers). But using some +tricks (described below), the pointers to F90 module objects can be +determined in runtime providing a compiler independent solution. + +To use Fortran objects from Python in unified manner, \fpy introduces +\texttt{PyFortranObject} to hold pointers of the Fortran objects and +the corresponing wrapper functions. In fact, \texttt{PyFortranObject} +does much more: it generates documentation strings in run-time (for +items in \texttt{COMMON} blocks and data in F90 modules), provides +methods for accessing Fortran data and for calling Fortran routines, +etc. + +\section{\texttt{PyFortranObject}} +\label{sec:pyfortobj} + +\texttt{PyFortranObject} is defined as follows +\begin{verbatim} +typedef struct { + PyObject_HEAD + int len; /* Number of attributes */ + FortranDataDef *defs; /* An array of FortranDataDef's */ + PyObject *dict; /* Fortran object attribute dictionary */ +} PyFortranObject; +\end{verbatim} +where \texttt{FortranDataDef} is +\begin{verbatim} +typedef struct { + char *name; /* attribute (array||routine) name */ + int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS, + || rank=-1 for Fortran routine */ + struct {int d[F2PY_MAX_DIMS];} dims; /* dimensions of the array, || not used */ + int type; /* PyArray_<type> || not used */ + char *data; /* pointer to array || Fortran routine */ + void (*func)(); /* initialization function for + allocatable arrays: + func(&rank,dims,set_ptr_func,name,len(name)) + || C/API wrapper for Fortran routine */ + char *doc; /* documentation string; only recommended + for routines. */ +} FortranDataDef; +\end{verbatim} +In the following we demonstrate typical usages of +\texttt{PyFortranObject}. Just relevant code fragments will be given. + + +\section{Fortran 77 subroutine} +\label{sec:f77subrout} + +Consider Fortran 77 subroutine +\begin{verbatim} +subroutine bar() +end +\end{verbatim} +The corresponding \texttt{PyFortranObject} is defined in C as follows: +\begin{verbatim} +static char doc_bar[] = "bar()"; +static PyObject *c_bar(PyObject *self, PyObject *args, + PyObject *keywds, void (*f2py_func)()) { + static char *capi_kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args,keywds,"|:bar",capi_kwlist)) + return NULL; + (*f2py_func)(); + return Py_BuildValue(""); +} +extern void F_FUNC(bar,BAR)(); +static FortranDataDef f2py_routines_def[] = { + {"bar",-1, {-1}, 0, (char *)F_FUNC(bar,BAR),(void*)c_bar,doc_bar}, + {NULL} +}; +void initfoo() { + <snip> + d = PyModule_GetDict(m); + PyDict_SetItemString(d, f2py_routines_def[0].name, + PyFortranObject_NewAsAttr(&f2py_routines_def[0])); +} +\end{verbatim} +where CPP macro \texttt{F\_FUNC} defines how Fortran 77 routines are +seen in C. +In Python, Fortran subroutine \texttt{bar} is called as follows +\begin{verbatim} +>>> import foo +>>> foo.bar() +\end{verbatim} + +\section{Fortran 77 function} +\label{sec:f77func} +Consider Fortran 77 function +\begin{verbatim} +function bar() +complex bar +end +\end{verbatim} +The corresponding \texttt{PyFortranObject} is defined in C as in +previous example but with the following changes: +\begin{verbatim} +static char doc_bar[] = "bar = bar()"; +static PyObject *c_bar(PyObject *self, PyObject *args, + PyObject *keywds, void (*f2py_func)()) { + complex_float bar; + static char *capi_kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args,keywds,"|:bar",capi_kwlist)) + return NULL; + (*f2py_func)(&bar); + return Py_BuildValue("O",pyobj_from_complex_float1(bar)); +} +extern void F_WRAPPEDFUNC(bar,BAR)(); +static FortranDataDef f2py_routines_def[] = { + {"bar",-1,{-1},0,(char *)F_WRAPPEDFUNC(bar,BAR),(void *)c_bar,doc_bar}, + {NULL} +}; +\end{verbatim} +where CPP macro \texttt{F\_WRAPPEDFUNC} gives the pointer to the following +Fortran 77 subroutine: +\begin{verbatim} +subroutine f2pywrapbar (barf2pywrap) +external bar +complex bar, barf2pywrap +barf2pywrap = bar() +end +\end{verbatim} +With these hooks, calling Fortran functions returning composed types +becomes platform/compiler independent. + + +\section{\texttt{COMMON} block data} +\label{sec:commondata} + +Consider Fortran 77 \texttt{COMMON} block +\begin{verbatim} +integer i +COMMON /bar/ i +\end{verbatim} +In order to access the variable \texttt{i} from Python, +\texttt{PyFortranObject} is defined as follows: +\begin{verbatim} +static FortranDataDef f2py_bar_def[] = { + {"i",0,{-1},PyArray_INT}, + {NULL} +}; +static void f2py_setup_bar(char *i) { + f2py_bar_def[0].data = i; +} +extern void F_FUNC(f2pyinitbar,F2PYINITBAR)(); +static void f2py_init_bar() { + F_FUNC(f2pyinitbar,F2PYINITBAR)(f2py_setup_bar); +} +void initfoo() { + <snip> + PyDict_SetItemString(d, "bar", PyFortranObject_New(f2py_bar_def,f2py_init_bar)); +} +\end{verbatim} +where auxiliary Fortran function \texttt{f2pyinitbar} is defined as follows +\begin{verbatim} +subroutine f2pyinitbar(setupfunc) +external setupfunc +integer i +common /bar/ i +call setupfunc(i) +end +\end{verbatim} +and it is called in \texttt{PyFortranObject\_New}. + + +\section{Fortran 90 module subroutine} +\label{sec:f90modsubrout} + +Consider +\begin{verbatim} +module fun + subroutine bar() + end subroutine bar +end module fun +\end{verbatim} +\texttt{PyFortranObject} is defined as follows +\begin{verbatim} +static char doc_fun_bar[] = "fun.bar()"; +static PyObject *c_fun_bar(PyObject *self, PyObject *args, + PyObject *keywds, void (*f2py_func)()) { + static char *kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args,keywds,"",kwlist)) + return NULL; + (*f2py_func)(); + return Py_BuildValue(""); +} +static FortranDataDef f2py_fun_def[] = { + {"bar",-1,{-1},0,NULL,(void *)c_fun_bar,doc_fun_bar}, + {NULL} +}; +static void f2py_setup_fun(char *bar) { + f2py_fun_def[0].data = bar; +} +extern void F_FUNC(f2pyinitfun,F2PYINITFUN)(); +static void f2py_init_fun() { + F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun); +} +void initfoo () { + <snip> + PyDict_SetItemString(d, "fun", PyFortranObject_New(f2py_fun_def,f2py_init_fun)); +} +\end{verbatim} +where auxiliary Fortran function \texttt{f2pyinitfun} is defined as +follows +\begin{verbatim} +subroutine f2pyinitfun(f2pysetupfunc) +use fun +external f2pysetupfunc +call f2pysetupfunc(bar) +end subroutine f2pyinitfun +\end{verbatim} +The following Python session demonstrates how to call Fortran 90 +module function \texttt{bar}: +\begin{verbatim} +>>> import foo +>>> foo.fun.bar() +\end{verbatim} + +\section{Fortran 90 module function} +\label{sec:f90modfunc} + +Consider +\begin{verbatim} +module fun + function bar() + complex bar + end subroutine bar +end module fun +\end{verbatim} +\texttt{PyFortranObject} is defined as follows +\begin{verbatim} +static char doc_fun_bar[] = "bar = fun.bar()"; +static PyObject *c_fun_bar(PyObject *self, PyObject *args, + PyObject *keywds, void (*f2py_func)()) { + complex_float bar; + static char *kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args,keywds,"",kwlist)) + return NULL; + (*f2py_func)(&bar); + return Py_BuildValue("O",pyobj_from_complex_float1(bar)); +} +static FortranDataDef f2py_fun_def[] = { + {"bar",-1,{-1},0,NULL,(void *)c_fun_bar,doc_fun_bar}, + {NULL} +}; +static void f2py_setup_fun(char *bar) { + f2py_fun_def[0].data = bar; +} +extern void F_FUNC(f2pyinitfun,F2PYINITFUN)(); +static void f2py_init_fun() { + F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun); +} +void initfoo() { + <snip> + PyDict_SetItemString(d, "fun", PyFortranObject_New(f2py_fun_def,f2py_init_fun)); +} +\end{verbatim} +where +\begin{verbatim} +subroutine f2pywrap_fun_bar (barf2pywrap) +use fun +complex barf2pywrap +barf2pywrap = bar() +end + +subroutine f2pyinitfun(f2pysetupfunc) +external f2pysetupfunc,f2pywrap_fun_bar +call f2pysetupfunc(f2pywrap_fun_bar) +end +\end{verbatim} + + +\section{Fortran 90 module data} +\label{sec:f90moddata} + +Consider +\begin{verbatim} +module fun + integer i +end module fun +\end{verbatim} +Then +\begin{verbatim} +static FortranDataDef f2py_fun_def[] = { + {"i",0,{-1},PyArray_INT}, + {NULL} +}; +static void f2py_setup_fun(char *i) { + f2py_fun_def[0].data = i; +} +extern void F_FUNC(f2pyinitfun,F2PYINITFUN)(); +static void f2py_init_fun() { + F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun); +} +void initfoo () { + <snip> + PyDict_SetItemString(d, "fun", + PyFortranObject_New(f2py_fun_def,f2py_init_fun)); +} +\end{verbatim} +where +\begin{verbatim} +subroutine f2pyinitfun(f2pysetupfunc) +use fun +external f2pysetupfunc +call f2pysetupfunc(i) +end subroutine f2pyinitfun +\end{verbatim} +Example usage in Python: +\begin{verbatim} +>>> import foo +>>> foo.fun.i = 4 +\end{verbatim} + +\section{Fortran 90 module allocatable array} +\label{sec:f90modallocarr} + +Consider +\begin{verbatim} +module fun + real, allocatable :: r(:) +end module fun +\end{verbatim} +Then +\begin{verbatim} +static FortranDataDef f2py_fun_def[] = { + {"r",1,{-1},PyArray_FLOAT}, + {NULL} +}; +static void f2py_setup_fun(void (*r)()) { + f2py_fun_def[0].func = r; +} +extern void F_FUNC(f2pyinitfun,F2PYINITFUN)(); +static void f2py_init_fun() { + F_FUNC(f2pyinitfun,F2PYINITFUN)(f2py_setup_fun); +} +void initfoo () { + <snip> + PyDict_SetItemString(d, "fun", PyFortranObject_New(f2py_fun_def,f2py_init_fun)); +} +\end{verbatim} +where +\begin{verbatim} +subroutine f2py_fun_getdims_r(r,s,f2pysetdata) +use fun, only: d => r +external f2pysetdata +logical ns +integer s(*),r,i,j +ns = .FALSE. +if (allocated(d)) then + do i=1,r + if ((size(d,r-i+1).ne.s(i)).and.(s(i).ge.0)) then + ns = .TRUE. + end if + end do + if (ns) then + deallocate(d) + end if +end if +if ((.not.allocated(d)).and.(s(1).ge.1)) then + allocate(d(s(1))) +end if +if (allocated(d)) then + do i=1,r + s(i) = size(d,r-i+1) + end do +end if +call f2pysetdata(d,allocated(d)) +end subroutine f2py_fun_getdims_r + +subroutine f2pyinitfun(f2pysetupfunc) +use fun +external f2pysetupfunc,f2py_fun_getdims_r +call f2pysetupfunc(f2py_fun_getdims_r) +end subroutine f2pyinitfun +\end{verbatim} +Usage in Python: +\begin{verbatim} +>>> import foo +>>> foo.fun.r = [1,2,3,4] +\end{verbatim} + +\section{Callback subroutine} +\label{sec:cbsubr} + +Thanks to Travis Oliphant for working out the basic idea of the +following callback mechanism. + +Consider +\begin{verbatim} +subroutine fun(bar) +external bar +call bar(1) +end +\end{verbatim} +Then +\begin{verbatim} +static char doc_foo8_fun[] = " +Function signature: + fun(bar,[bar_extra_args]) +Required arguments: + bar : call-back function +Optional arguments: + bar_extra_args := () input tuple +Call-back functions: + def bar(e_1_e): return + Required arguments: + e_1_e : input int"; +static PyObject *foo8_fun(PyObject *capi_self, PyObject *capi_args, + PyObject *capi_keywds, void (*f2py_func)()) { + PyObject *capi_buildvalue = NULL; + PyObject *bar_capi = Py_None; + PyTupleObject *bar_xa_capi = NULL; + PyTupleObject *bar_args_capi = NULL; + jmp_buf bar_jmpbuf; + int bar_jmpbuf_flag = 0; + int bar_nofargs_capi = 0; + static char *capi_kwlist[] = {"bar","bar_extra_args",NULL}; + + if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\ + "O!|O!:foo8.fun",\ + capi_kwlist,&PyFunction_Type,&bar_capi,&PyTuple_Type,&bar_xa_capi)) + goto capi_fail; + + bar_nofargs_capi = cb_bar_in_fun__user__routines_nofargs; + if (create_cb_arglist(bar_capi,bar_xa_capi,1,0, + &cb_bar_in_fun__user__routines_nofargs,&bar_args_capi)) { + if ((PyErr_Occurred())==NULL) + PyErr_SetString(foo8_error,"failed in processing argument list for call-back bar." ); + goto capi_fail; + } + + SWAP(bar_capi,cb_bar_in_fun__user__routines_capi,PyObject); + SWAP(bar_args_capi,cb_bar_in_fun__user__routines_args_capi,PyTupleObject); + memcpy(&bar_jmpbuf,&cb_bar_in_fun__user__routines_jmpbuf,sizeof(jmp_buf)); + bar_jmpbuf_flag = 1; + + if ((setjmp(cb_bar_in_fun__user__routines_jmpbuf))) { + if ((PyErr_Occurred())==NULL) + PyErr_SetString(foo8_error,"Failure of a callback function"); + goto capi_fail; + } else + (*f2py_func)(cb_bar_in_fun__user__routines); + + capi_buildvalue = Py_BuildValue(""); +capi_fail: + + if (bar_jmpbuf_flag) { + cb_bar_in_fun__user__routines_capi = bar_capi; + Py_DECREF(cb_bar_in_fun__user__routines_args_capi); + cb_bar_in_fun__user__routines_args_capi = bar_args_capi; + cb_bar_in_fun__user__routines_nofargs = bar_nofargs_capi; + memcpy(&cb_bar_in_fun__user__routines_jmpbuf,&bar_jmpbuf,sizeof(jmp_buf)); + bar_jmpbuf_flag = 0; + } + return capi_buildvalue; +} +extern void F_FUNC(fun,FUN)(); +static FortranDataDef f2py_routine_defs[] = { + {"fun",-1,{-1},0,(char *)F_FUNC(fun,FUN),(void *)foo8_fun,doc_foo8_fun}, + {NULL} +}; +void initfoo8 () { + <snip> + PyDict_SetItemString(d, f2py_routine_defs[0].name, + PyFortranObject_NewAsAttr(&f2py_routine_defs[0])); +} +\end{verbatim} +where +\begin{verbatim} +PyObject *cb_bar_in_fun__user__routines_capi = Py_None; +PyTupleObject *cb_bar_in_fun__user__routines_args_capi = NULL; +int cb_bar_in_fun__user__routines_nofargs = 0; +jmp_buf cb_bar_in_fun__user__routines_jmpbuf; +static void cb_bar_in_fun__user__routines (int *e_1_e_cb_capi) { + PyTupleObject *capi_arglist = cb_bar_in_fun__user__routines_args_capi; + PyObject *capi_return = NULL; + PyObject *capi_tmp = NULL; + int capi_j,capi_i = 0; + + int e_1_e=(*e_1_e_cb_capi); + if (capi_arglist == NULL) + goto capi_fail; + if (cb_bar_in_fun__user__routines_nofargs>capi_i) + if (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyobj_from_int1(e_1_e))) + goto capi_fail; + + capi_return = PyEval_CallObject(cb_bar_in_fun__user__routines_capi, + (PyObject *)capi_arglist); + + if (capi_return == NULL) + goto capi_fail; + if (capi_return == Py_None) { + Py_DECREF(capi_return); + capi_return = Py_BuildValue("()"); + } + else if (!PyTuple_Check(capi_return)) { + capi_tmp = capi_return; + capi_return = Py_BuildValue("(O)",capi_tmp); + Py_DECREF(capi_tmp); + } + capi_j = PyTuple_Size(capi_return); + capi_i = 0; + goto capi_return_pt; +capi_fail: + fprintf(stderr,"Call-back cb_bar_in_fun__user__routines failed.\n"); + Py_XDECREF(capi_return); + longjmp(cb_bar_in_fun__user__routines_jmpbuf,-1); +capi_return_pt: + ; +} +\end{verbatim} +Usage in Python: +\begin{verbatim} +>>> import foo8 as foo +>>> def bar(i): print 'In bar i=',i +... +>>> foo.fun(bar) +In bar i= 1 +\end{verbatim} + +\end{document} + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: diff --git a/numpy/f2py/doc/index.html b/numpy/f2py/doc/index.html new file mode 100644 index 000000000..abddd7d43 --- /dev/null +++ b/numpy/f2py/doc/index.html @@ -0,0 +1,265 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> +<HTML> +<HEAD> +<META name="Author" content="Pearu Peterson"> +<!-- You may add here some keywords (comma separeted list) --> +<META name="Keywords" content="fortran,python,interface,f2py,f2py2e,wrapper,fpig"> +<TITLE>F2PY - Fortran to Python Interface Generator</TITLE> +<LINK rel="stylesheet" type="text/css" href="/styles/userstyle.css"> +</HEAD> + +<BODY> +<!-- Begin of user text --> +<H1>F2PY ­ Fortran to Python Interface Generator</H1> +by <em>Pearu Peterson</em> + +<h2>What's new?</h2> + +See <a href="NEWS.txt">NEWS.txt</a> for the latest changes in <code>f2py</code>. +<dl> + <dt> July ??, 2002 + <dd> Implemented prototype calculator, complete tests for scalar F77 + functions, --help-compiler option. Fixed number of bugs and + removed obsolete features. + <dt> April 4, 2002 + <dd> Fixed a nasty bug of copying one-dimensional non-contiguous arrays. + (Thanks to Travis O. for pointing this out). + <dt> March 26, 2002 + <dd> Bug fixes, turned off F2PY_REPORT_ATEXIT by default. + <dt> March 13, 2002 + <dd> MAC support, fixed incomplete dependency calculator, minor bug fixes. + <dt> March 3, 2002 + <dd> Fixed memory leak and copying of multi-dimensional complex arrays. + <dt> <a href="oldnews.html">Old news</a>. +</dl> + +<h2>Introduction</h2> + +Writing Python C/API wrappers for Fortran routines can be a very +tedious task, especially if a Fortran routine takes more than 20 +arguments but only few of them are relevant for the problems that they +solve. So, I have developed a tool that generates the C/API modules +containing wrapper functions of Fortran routines. I call this +tool as <em>F2PY ­ Fortran to Python Interface Generator</em>. +It is completely written in <a href="http://www.python.org">Python</a> +language and can be called from the command line as <code>f2py</code>. +<em>F2PY</em> is released under the terms of <a +href="http://www.fsf.org/copyleft/lesser.html">GNU LGPL</a>. + + +<h2><code>f2py</code>, Second Edition</h2> + +The development of <code>f2py</code> started in summer of 1999. +For now (January, 2000) it has reached to stage of being a +complete tool: it scans real Fortran code, creates signature file +that the user can modify, constructs C/API module that can be +complied and imported to Python, and it creates LaTeX documentation +for wrapper functions. Below is a bit longer list of +<code>f2py</code> features: +<ol> + <li> <code>f2py</code> scans real Fortran codes and produces the signature files. + The syntax of the signature files is borrowed from the Fortran 90/95 + language specification with some extensions. + <li> <code>f2py</code> generates a GNU Makefile that can be used + for building shared modules (see below for a list of supported + platforms/compilers). Starting from the third release, + <code>f2py</code> generates <code>setup_modulename.py</code> for + building extension modules using <code>distutils</code> tools. + <li> <code>f2py</code> uses the signature files to produce the wrappers for + Fortran 77 routines and their <code>COMMON</code> blocks. + <li> For <code>external</code> arguments <code>f2py</code> constructs a very flexible + call-back mechanism so that Python functions can be called from + Fortran. + <li> You can pass in almost arbitrary Python objects to wrapper + functions. If needed, <code>f2py</code> takes care of type-casting and + non-contiguous arrays. + <li> You can modify the signature files so that <code>f2py</code> will generate + wrapper functions with desired signatures. <code>depend()</code> + attribute is introduced to control the initialization order of the + variables. <code>f2py</code> introduces <code>intent(hide)</code> + attribute to remove + the particular argument from the argument list of the wrapper + function and <code>intent(c)</code> that is useful for wrapping C +libraries. In addition, <code>optional</code> and +<code>required</code> + attributes are introduced and employed. + <li> <code>f2py</code> supports almost all standard Fortran 77/90/95 constructs + and understands all basic Fortran types, including + (multi-dimensional, complex) arrays and character strings with + adjustable and assumed sizes/lengths. + <li> <code>f2py</code> generates a LaTeX document containing the + documentations of the wrapped functions (argument types, dimensions, + etc). The user can easily add some human readable text to the + documentation by inserting <code>note(<LaTeX text>)</code> attribute to + the definition of routine signatures. + <li> With <code>f2py</code> one can access also Fortran 90/95 + module subroutines from Python. +</ol> + +For more information, see the <a href="usersguide.html">User's +Guide</a> of the tool. Windows users should also take a look at +<a href="win32_notes.txt">f2py HOWTO for Win32</a> (its latest version +can be found <a +href="http://www.scipy.org/Members/eric/f2py_win32">here</a>). + +<h3>Requirements</h3> +<ol> + <li> You'll need <a + href="http://www.python.org/download/">Python</a> + (1.5.2 or later, 2.2 is recommended) to run <code>f2py</code> + (because it uses exchanged module <code>re</code>). + To build generated extension modules with distutils setup script, + you'll need Python 2.x. + <li> You'll need <a + href="http://sourceforge.net/project/?group_id=1369">Numerical + Python</a> + (version 13 or later, 20.3 is recommended) to compile + C/API modules (because they use function + <code>PyArray_FromDimsAndDataAndDescr</code>) +</ol> + +<h3>Download</h3> + +<dl> + <dt> User's Guide: + <dd> <a href="usersguide.html">usersguide.html</a>, + <a href="usersguide.pdf">usersguide.pdf</a>, + <a href="usersguide.ps.gz">usersguide.ps.gz</a>, + <a href="usersguide.dvi">usersguide.dvi</a>. + <dt> Snapshots of the fifth public release: + <dd> <a href="2.x">2.x</a>/<a href="2.x/F2PY-2-latest.tar.gz">F2PY-2-latest.tar.gz</a> + <dt> Snapshots of earlier releases: + <dd> <a href="rel-5.x">rel-5.x</a>, <a href="rel-4.x">rel-4.x</a>, + <a href="rel-3.x">rel-3.x</a>, + <a href="rel-2.x">rel-2.x</a>,<a href="rel-1.x">rel-1.x</a>, + <a href="rel-0.x">rel-0.x</a> +</dl> + +<h3>Installation</h3> + +Unpack the source file, change to directory <code>f2py-?-???</code> +and run <code>python setup.py install</code>. That's it! + +<h3>Platform/Compiler Related Notes</h3> + +<code>f2py</code> has been successfully tested on +<ul> + <li> Intel Linux (MD7.0,RH6.1,RH4.2,Debian woody), Athlon Linux (RH6.1), Alpha Linux (RH5.2,RH6.1) with <a +href="http://gcc.gnu.org/">gcc</a> (versions egcs-2.91.60,egcs-2.91.66, and 2.95.2). + <li> Intel Linux (MD7.0) with <a + href="http://www.psrv.com/index.html">Pacific-Sierra + Research</a> <a href="http://www.psrv.com/lnxf90.html">Personal + Linux VAST/f90 Fortran 90 compiler</a> (version V3.4N5). + <li> Intel Linux (RH6.1) with <a href="http://www.absoft.com/">Absoft F77/F90</a> compilers for Linux. + <li> IRIX64 with <a href="http://gcc.gnu.org/">gcc</a> (2.95.2) and <a +href="http://www.sgi.com/developers/devtools/languages/mipspro.html">MIPSpro +7 Compilers</a> (f77,f90,cc versions 7.30). + <li> Alpha Linux (RH5.2,RH6.1) with <a href="http://www.digital.com/fortran/linux/">Compaq Fortran </a> compiler (version V1.0-920). + <li> Linux with <a href="http://www.nag.co.uk/">NAGWare</a> Fortran + 95 compiler. + <li> <a href="http://developer.intel.com/software/products/compilers/f50/linux/"> + Intel(R) Fortran Compiler for Linux</a> + <li> Windows 2000 with <a href="http://www.mingw.org">mingw32</a>. +</ul> +<code>f2py</code> will probably run on other UN*X systems as +well. Additions to the list of platforms/compilers where +<code>f2py</code> has been successfully used are most welcome. +<P> +<em>Note:</em> +Using Compaq Fortran +compiler on Alpha Linux is succesful unless when +wrapping Fortran callback functions returning +<code>COMPLEX</code>. This applies also for IRIX64. +<P> +<em>Note:</em> +Fortran 90/95 module support is currently tested with Absoft F90, VAST/f90, Intel F90 compilers on Linux (MD7.0,Debian woody). + + +<h3><a name="f2py-users">Mailing list</a></h3> + +There is a mailing list <a +href="http://cens.ioc.ee/pipermail/f2py-users/">f2py-users</a> +available for the users of the <code>f2py</code> +program and it is open for discussion, questions, and answers. You can subscribe +the list <a href="http://cens.ioc.ee/mailman/listinfo/f2py-users">here</a>. + +<h3><a href="http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/">CVS Repository</a></h3> + +<code>f2py</code> is being developed under <a href="http://www.sourcegear.com/CVS">CVS</a> and those who are +interested in the really latest version of <code>f2py</code> (possibly +unstable) can get it from the repository as follows: +<ol> + <li> First you need to login (the password is <code>guest</code>): +<pre> +> cvs -d :pserver:anonymous@cens.ioc.ee:/home/cvs login +</pre> + <li> and then do the checkout: +<pre> +> cvs -z6 -d :pserver:anonymous@cens.ioc.ee:/home/cvs checkout f2py2e +</pre> + <li> In the directory <code>f2py2e</code> you can get the updates by hitting +<pre> +> cvs -z6 update -P -d +</pre> +</ol> +You can browse <code>f2py</code> CVS repository <a href="http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/">here</a>. + +<h2>Related sites</h2> + +<ol> + <li> <a href="http://pfdubois.com/numpy/" target="_top">Numerical Python</a>. + <li> <a href="http://pyfortran.sourceforge.net/" target="_top">Pyfort</a> -- The Python-Fortran connection tool. + <li> <a href="http://starship.python.net/crew/hinsen/scientific.html" target="_top">Scientific Python</a>. + <li> <a href="http://scipy.org/" target="_top">SciPy</a> -- Scientific tools for Python (includes Multipack). + <li> <a href="http://www.fortran.com/fortran/" target="_top">The Fortran Company</a>. + <li> <a href="http://www.j3-fortran.org/" target="_top">Fortran Standards</a>. + + <li> <a href="http://www.fortran.com/fortran/F77_std/rjcnf.html">American National Standard Programming Language FORTRAN ANSI(R) X3.9-1978</a> + <li> <a href="http://www.mathtools.net" target="_top">Mathtools.net</a> -- A technical computing portal for all scientific and engineering needs. + +</ol> + +<!-- End of user text --> +<HR> +<ADDRESS> +<A href="http://validator.w3.org/"><IMG border=0 align=right src="/icons/vh40.gif" alt="Valid HTML 4.0!" height=31 width=88></A> +<A href="http://cens.ioc.ee/~pearu/" target="_top">Pearu Peterson</A> +<A href="mailto:pearu(at)ioc.ee"><pearu(at)ioc.ee></A><BR> +<!-- hhmts start --> +Last modified: Mon Dec 3 19:40:26 EET 2001 +<!-- hhmts end --> +</ADDRESS> +<!-- You may want to comment the following line out when the document is final--> +<!-- Check that the reference is right --> +<!--A href="http://validator.w3.org/check?uri=http://cens.ioc.ee/projects/f2py2e/index.html;ss"> Submit this page for validation</A--> + +<p> +<center> +This <a href="http://www.ctv.es/USERS/irmina/pythonring.html">Python +ring</a> site owned by <a href="mailto:pearu(at)ioc.ee">Pearu Peterson</a>. +<br> +[ + <a href="http://nav.webring.org/cgi-bin/navcgi?ring=python_ring;id=12;prev5">Previous 5 Sites</a> +| + <a href="http://nav.webring.org/cgi-bin/navcgi?ring=python_ring;id=12;prev">Previous</a> +| + <a href="http://nav.webring.org/cgi-bin/navcgi?ring=python_ring;id=12;next">Next</a> +| + <a href="http://nav.webring.org/cgi-bin/navcgi?ring=python_ring;id=12;next5">Next 5 Sites</a> +| + <a href="http://nav.webring.org/cgi-bin/navcgi?ring=python_ring;random">Random Site</a> +| + <a href="http://nav.webring.org/cgi-bin/navcgi?ring=python_ring;list">List Sites</a> +] +</center> +<p> + + + +</BODY> + + +</HTML> + + + diff --git a/numpy/f2py/doc/intro.tex b/numpy/f2py/doc/intro.tex new file mode 100644 index 000000000..d9625b09c --- /dev/null +++ b/numpy/f2py/doc/intro.tex @@ -0,0 +1,158 @@ + +\section{Introduction} +\label{sec:intro} + +\fpy is a command line tool that generates Python C/API modules for +interfacing Fortran~77/90/95 codes and Fortran~90/95 modules from +Python. In general, using \fpy an +interface is produced in three steps: +\begin{itemize} +\item[(i)] \fpy scans Fortran sources and creates the so-called + \emph{signature} file; the signature file contains the signatures of + Fortran routines; the signatures are given in the free format of the + Fortran~90/95 language specification. Latest version of \fpy + generates also a make file for building shared module. + About currently supported compilers see the \fpy home page +\item[(ii)] Optionally, the signature files can be modified manually + in order to dictate how the Fortran routines should be called or + seemed from the Python environment. +\item[(iii)] \fpy reads the signature files and generates Python C/API + modules that can be compiled and imported to Python code. In + addition, a LaTeX document is generated that contains the + documentation of wrapped functions. +\end{itemize} +(Note that if you are satisfied with the default signature that \fpy +generates in step (i), all three steps can be covered with just +one call to \fpy --- by not specifying `\texttt{-h}' flag). +Latest versions of \fpy support so-called \fpy directive that allows +inserting various information about wrapping directly to Fortran +source code as comments (\texttt{<comment char>f2py <signature statement>}). + +The following diagram illustrates the usage of the tool: +\begin{verbatim} +! Fortran file foo.f: + subroutine foo(a) + integer a + a = a + 5 + end +\end{verbatim} +\begin{verbatim} +! Fortran file bar.f: + function bar(a,b) + integer a,b,bar + bar = a + b + end +\end{verbatim} +\begin{itemize} +\item[(i)] \shell{\fpy foo.f bar.f -m foobar -h foobar.pyf} +\end{itemize} +\begin{verbatim} +!%f90 +! Signature file: foobar.pyf +python module foobar ! in + interface ! in :foobar + subroutine foo(a) ! in :foobar:foo.f + integer intent(inout) :: a + end subroutine foo + function bar(a,b) ! in :foobar:bar.f + integer :: a + integer :: b + integer :: bar + end function bar + end interface +end python module foobar +\end{verbatim} +\begin{itemize} +\item[(ii)] Edit the signature file (here I made \texttt{foo}s + argument \texttt{a} to be \texttt{intent(inout)}, see + Sec.~\ref{sec:attributes}). +\item[(iii)] \shell{\fpy foobar.pyf} +\end{itemize} +\begin{verbatim} +/* Python C/API module: foobarmodule.c */ +... +\end{verbatim} +\begin{itemize} +\item[(iv)] \shell{make -f Makefile-foobar} +%\shell{gcc -shared -I/usr/include/python1.5/ foobarmodule.c\bs\\ +%foo.f bar.f -o foobarmodule.so} +\end{itemize} +\begin{verbatim} +Python shared module: foobarmodule.so +\end{verbatim} +\begin{itemize} +\item[(v)] Usage in Python: +\end{itemize} +\vspace*{-4ex} +\begin{verbatim} +>>> import foobar +>>> print foobar.__doc__ +This module 'foobar' is auto-generated with f2py (version:1.174). +The following functions are available: + foo(a) + bar = bar(a,b) +. +>>> print foobar.bar(2,3) +5 +>>> from Numeric import * +>>> a = array(3) +>>> print a,foobar.foo(a),a +3 None 8 +\end{verbatim} +Information about how to call \fpy (steps (i) and (iii)) can be +obtained by executing\\ +\shell{\fpy}\\ +This will print the usage instructions. + Step (iv) is system dependent +(compiler and the locations of the header files \texttt{Python.h} and +\texttt{arrayobject.h}), and so you must know how to compile a shared +module for Python in you system. + +The next Section describes the step (ii) in more detail in order to +explain how you can influence to the process of interface generation +so that the users can enjoy more writing Python programs using your +wrappers that call Fortran routines. Step (v) is covered in +Sec.~\ref{sec:notes}. + + +\subsection{Features} +\label{sec:features} + +\fpy has the following features: +\begin{enumerate} +\item \fpy scans real Fortran codes and produces the signature files. + The syntax of the signature files is borrowed from the Fortran~90/95 + language specification with some extensions. +\item \fpy uses the signature files to produce the wrappers for + Fortran~77 routines and their \texttt{COMMON} blocks. +\item For \texttt{external} arguments \fpy constructs a very flexible + call-back mechanism so that Python functions can be called from + Fortran. +\item You can pass in almost arbitrary Python objects to wrapper + functions. If needed, \fpy takes care of type-casting and + non-contiguous arrays. +\item You can modify the signature files so that \fpy will generate + wrapper functions with desired signatures. \texttt{depend()} + attribute is introduced to control the initialization order of the + variables. \fpy introduces \texttt{intent(hide)} attribute to remove + the particular argument from the argument list of the wrapper + function. In addition, \texttt{optional} and \texttt{required} + attributes are introduced and employed. +\item \fpy supports almost all standard Fortran~77/90/95 constructs + and understands all basic Fortran types, including + (multi-dimensional, complex) arrays and character strings with + adjustable and assumed sizes/lengths. +\item \fpy generates a LaTeX document containing the + documentations of the wrapped functions (argument types, dimensions, + etc). The user can easily add some human readable text to the + documentation by inserting \texttt{note(<LaTeX text>)} attribute to + the definition of routine signatures. +\item \fpy generates a GNU make file that can be used for building + shared modules calling Fortran functions. +\item \fpy supports wrapping Fortran 90/95 module routines. +\end{enumerate} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: diff --git a/numpy/f2py/doc/multiarray/array_from_pyobj.c b/numpy/f2py/doc/multiarray/array_from_pyobj.c new file mode 100644 index 000000000..7e0de9a74 --- /dev/null +++ b/numpy/f2py/doc/multiarray/array_from_pyobj.c @@ -0,0 +1,323 @@ +/* + * File: array_from_pyobj.c + * + * Description: + * ------------ + * Provides array_from_pyobj function that returns a contigious array + * object with the given dimensions and required storage order, either + * in row-major (C) or column-major (Fortran) order. The function + * array_from_pyobj is very flexible about its Python object argument + * that can be any number, list, tuple, or array. + * + * array_from_pyobj is used in f2py generated Python extension + * modules. + * + * Author: Pearu Peterson <pearu@cens.ioc.ee> + * Created: 13-16 January 2002 + * $Id: array_from_pyobj.c,v 1.1 2002/01/16 18:57:33 pearu Exp $ + */ + + +#define ARR_IS_NULL(arr,mess) \ +if (arr==NULL) { \ + fprintf(stderr,"array_from_pyobj:" mess); \ + return NULL; \ +} + +#define CHECK_DIMS_DEFINED(rank,dims,mess) \ +if (count_nonpos(rank,dims)) { \ + fprintf(stderr,"array_from_pyobj:" mess); \ + return NULL; \ +} + +#define HAS_PROPER_ELSIZE(arr,type_num) \ + ((PyArray_DescrFromType(type_num)->elsize) == (arr)->descr->elsize) + +/* static */ +/* void f2py_show_args(const int type_num, */ +/* const int *dims, */ +/* const int rank, */ +/* const int intent) { */ +/* int i; */ +/* fprintf(stderr,"array_from_pyobj:\n\ttype_num=%d\n\trank=%d\n\tintent=%d\n",\ */ +/* type_num,rank,intent); */ +/* for (i=0;i<rank;++i) */ +/* fprintf(stderr,"\tdims[%d]=%d\n",i,dims[i]); */ +/* } */ + +static +int count_nonpos(const int rank, + const int *dims) { + int i=0,r=0; + while (i<rank) { + if (dims[i] <= 0) ++r; + ++i; + } + return r; +} + +static void lazy_transpose(PyArrayObject* arr); +static int check_and_fix_dimensions(const PyArrayObject* arr, + const int rank, + int *dims); +static +int array_has_column_major_storage(const PyArrayObject *ap); + +static +PyArrayObject* array_from_pyobj(const int type_num, + int *dims, + const int rank, + const int intent, + PyObject *obj) { + /* Note about reference counting + ----------------------------- + If the caller returns the array to Python, it must be done with + Py_BuildValue("N",arr). + Otherwise, if obj!=arr then the caller must call Py_DECREF(arr). + */ + +/* f2py_show_args(type_num,dims,rank,intent); */ + + if (intent & F2PY_INTENT_CACHE) { + /* Don't expect correct storage order or anything reasonable when + returning cache array. */ + if ((intent & F2PY_INTENT_HIDE) + || (obj==Py_None)) { + PyArrayObject *arr = NULL; + CHECK_DIMS_DEFINED(rank,dims,"optional,intent(cache) must" + " have defined dimensions.\n"); + arr = (PyArrayObject *)PyArray_FromDims(rank,dims,type_num); + ARR_IS_NULL(arr,"FromDims failed: optional,intent(cache)\n"); + if (intent & F2PY_INTENT_OUT) + Py_INCREF(arr); + return arr; + } + if (PyArray_Check(obj) + && ISCONTIGUOUS((PyArrayObject *)obj) + && HAS_PROPER_ELSIZE((PyArrayObject *)obj,type_num) + ) { + if (check_and_fix_dimensions((PyArrayObject *)obj,rank,dims)) + return NULL; /*XXX: set exception */ + if (intent & F2PY_INTENT_OUT) + Py_INCREF(obj); + return (PyArrayObject *)obj; + } + ARR_IS_NULL(NULL,"intent(cache) must be contiguous array with a proper elsize.\n"); + } + + if (intent & F2PY_INTENT_HIDE) { + PyArrayObject *arr = NULL; + CHECK_DIMS_DEFINED(rank,dims,"intent(hide) must have defined dimensions.\n"); + arr = (PyArrayObject *)PyArray_FromDims(rank,dims,type_num); + ARR_IS_NULL(arr,"FromDims failed: intent(hide)\n"); + if (intent & F2PY_INTENT_OUT) { + if ((!(intent & F2PY_INTENT_C)) && (rank>1)) { + lazy_transpose(arr); + arr->flags &= ~CONTIGUOUS; + } + Py_INCREF(arr); + } + return arr; + } + + if (PyArray_Check(obj)) { /* here we have always intent(in) or + intent(inout) */ + + PyArrayObject *arr = (PyArrayObject *)obj; + int is_cont = (intent & F2PY_INTENT_C) ? + (ISCONTIGUOUS(arr)) : (array_has_column_major_storage(arr)); + + if (check_and_fix_dimensions(arr,rank,dims)) + return NULL; /*XXX: set exception */ + + if ((intent & F2PY_INTENT_COPY) + || (! (is_cont + && HAS_PROPER_ELSIZE(arr,type_num) + && PyArray_CanCastSafely(arr->descr->type_num,type_num)))) { + PyArrayObject *tmp_arr = NULL; + if (intent & F2PY_INTENT_INOUT) { + ARR_IS_NULL(NULL,"intent(inout) array must be contiguous and" + " with a proper type and size.\n") + } + if ((rank>1) && (! (intent & F2PY_INTENT_C))) + lazy_transpose(arr); + if (PyArray_CanCastSafely(arr->descr->type_num,type_num)) { + tmp_arr = (PyArrayObject *)PyArray_CopyFromObject(obj,type_num,0,0); + ARR_IS_NULL(arr,"CopyFromObject failed: array.\n"); + } else { + tmp_arr = (PyArrayObject *)PyArray_FromDims(arr->nd, + arr->dimensions, + type_num); + ARR_IS_NULL(tmp_arr,"FromDims failed: array with unsafe cast.\n"); + if (copy_ND_array(arr,tmp_arr)) + ARR_IS_NULL(NULL,"copy_ND_array failed: array with unsafe cast.\n"); + } + if ((rank>1) && (! (intent & F2PY_INTENT_C))) { + lazy_transpose(arr); + lazy_transpose(tmp_arr); + tmp_arr->flags &= ~CONTIGUOUS; + } + arr = tmp_arr; + } + if (intent & F2PY_INTENT_OUT) + Py_INCREF(arr); + return arr; + } + + if ((obj==Py_None) && (intent & F2PY_OPTIONAL)) { + PyArrayObject *arr = NULL; + CHECK_DIMS_DEFINED(rank,dims,"optional must have defined dimensions.\n"); + arr = (PyArrayObject *)PyArray_FromDims(rank,dims,type_num); + ARR_IS_NULL(arr,"FromDims failed: optional.\n"); + if (intent & F2PY_INTENT_OUT) { + if ((!(intent & F2PY_INTENT_C)) && (rank>1)) { + lazy_transpose(arr); + arr->flags &= ~CONTIGUOUS; + } + Py_INCREF(arr); + } + return arr; + } + + if (intent & F2PY_INTENT_INOUT) { + ARR_IS_NULL(NULL,"intent(inout) argument must be an array.\n"); + } + + { + PyArrayObject *arr = (PyArrayObject *) \ + PyArray_ContiguousFromObject(obj,type_num,0,0); + ARR_IS_NULL(arr,"ContiguousFromObject failed: not a sequence.\n"); + if (check_and_fix_dimensions(arr,rank,dims)) + return NULL; /*XXX: set exception */ + if ((rank>1) && (! (intent & F2PY_INTENT_C))) { + PyArrayObject *tmp_arr = NULL; + lazy_transpose(arr); + arr->flags &= ~CONTIGUOUS; + tmp_arr = (PyArrayObject *) PyArray_CopyFromObject((PyObject *)arr,type_num,0,0); + Py_DECREF(arr); + arr = tmp_arr; + ARR_IS_NULL(arr,"CopyFromObject(Array) failed: intent(fortran)\n"); + lazy_transpose(arr); + arr->flags &= ~CONTIGUOUS; + } + if (intent & F2PY_INTENT_OUT) + Py_INCREF(arr); + return arr; + } + +} + + /*****************************************/ + /* Helper functions for array_from_pyobj */ + /*****************************************/ + +static +int array_has_column_major_storage(const PyArrayObject *ap) { + /* array_has_column_major_storage(a) is equivalent to + transpose(a).iscontiguous() but more efficient. + + This function can be used in order to decide whether to use a + Fortran or C version of a wrapped function. This is relevant, for + example, in choosing a clapack or flapack function depending on + the storage order of array arguments. + */ + int sd; + int i; + sd = ap->descr->elsize; + for (i=0;i<ap->nd;++i) { + if (ap->dimensions[i] == 0) return 1; + if (ap->strides[i] != sd) return 0; + sd *= ap->dimensions[i]; + } + return 1; +} + +static +void lazy_transpose(PyArrayObject* arr) { + /* + Changes the order of array strides and dimensions. This + corresponds to the lazy transpose of a Numeric array in-situ. + Note that this function is assumed to be used even times for a + given array. Otherwise, the caller should set flags &= ~CONTIGUOUS. + */ + int rank,i,s,j; + rank = arr->nd; + if (rank < 2) return; + + for(i=0,j=rank-1;i<rank/2;++i,--j) { + s = arr->strides[i]; + arr->strides[i] = arr->strides[j]; + arr->strides[j] = s; + s = arr->dimensions[i]; + arr->dimensions[i] = arr->dimensions[j]; + arr->dimensions[j] = s; + } +} + +static +int check_and_fix_dimensions(const PyArrayObject* arr,const int rank,int *dims) { + /* + This function fills in blanks (that are -1's) in dims list using + the dimensions from arr. It also checks that non-blank dims will + match with the corresponding values in arr dimensions. + */ + const int arr_size = (arr->nd)?PyArray_Size((PyObject *)arr):1; + + if (rank > arr->nd) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */ + int new_size = 1; + int free_axe = -1; + int i; + /* Fill dims where -1 or 0; check dimensions; calc new_size; */ + for(i=0;i<arr->nd;++i) { + if (dims[i] >= 0) { + if (dims[i]!=arr->dimensions[i]) { + fprintf(stderr,"%d-th dimension must be fixed to %d but got %d\n", + i,dims[i],arr->dimensions[i]); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else { + dims[i] = arr->dimensions[i] ? arr->dimensions[i] : 1; + } + new_size *= dims[i]; + } + for(i=arr->nd;i<rank;++i) + if (dims[i]>1) { + fprintf(stderr,"%d-th dimension must be %d but got 0 (not defined).\n", + i,dims[i]); + return 1; + } else if (free_axe<0) + free_axe = i; + else + dims[i] = 1; + if (free_axe>=0) { + dims[free_axe] = arr_size/new_size; + new_size *= dims[free_axe]; + } + if (new_size != arr_size) { + fprintf(stderr,"confused: new_size=%d, arr_size=%d (maybe too many free" + " indices)\n",new_size,arr_size); + return 1; + } + } else { + int i; + for (i=rank;i<arr->nd;++i) + if (arr->dimensions[i]>1) { + fprintf(stderr,"too many axes: %d, expected rank=%d\n",arr->nd,rank); + return 1; + } + for (i=0;i<rank;++i) + if (dims[i]>=0) { + if (arr->dimensions[i]!=dims[i]) { + fprintf(stderr,"%d-th dimension must be fixed to %d but got %d\n", + i,dims[i],arr->dimensions[i]); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else + dims[i] = arr->dimensions[i]; + } + return 0; +} + +/* End of file: array_from_pyobj.c */ diff --git a/numpy/f2py/doc/multiarray/bar.c b/numpy/f2py/doc/multiarray/bar.c new file mode 100644 index 000000000..350636ea6 --- /dev/null +++ b/numpy/f2py/doc/multiarray/bar.c @@ -0,0 +1,15 @@ + +#include <stdio.h> + +void bar(int *a,int m,int n) { + int i,j; + printf("C:"); + printf("m=%d, n=%d\n",m,n); + for (i=0;i<m;++i) { + printf("Row %d:\n",i+1); + for (j=0;j<n;++j) + printf("a(i=%d,j=%d)=%d\n",i,j,a[n*i+j]); + } + if (m*n) + a[0] = 7777; +} diff --git a/numpy/f2py/doc/multiarray/foo.f b/numpy/f2py/doc/multiarray/foo.f new file mode 100644 index 000000000..f8c39c4d1 --- /dev/null +++ b/numpy/f2py/doc/multiarray/foo.f @@ -0,0 +1,13 @@ + subroutine foo(a,m,n) + integer a(m,n), m,n,i,j + print*, "F77:" + print*, "m=",m,", n=",n + do 100,i=1,m + print*, "Row ",i,":" + do 50,j=1,n + print*, "a(i=",i,",j=",j,") = ",a(i,j) + 50 continue + 100 continue + if (m*n.gt.0) a(1,1) = 77777 + end + diff --git a/numpy/f2py/doc/multiarray/fortran_array_from_pyobj.txt b/numpy/f2py/doc/multiarray/fortran_array_from_pyobj.txt new file mode 100644 index 000000000..c7b945c84 --- /dev/null +++ b/numpy/f2py/doc/multiarray/fortran_array_from_pyobj.txt @@ -0,0 +1,284 @@ + + _____________________________________________________________ + / Proposed internal structure for f2py generated extension \ + < modules regarding the issues with different storage-orders > + \ of multi-dimensional matrices in Fortran and C. / + ============================================================= + +Author: Pearu Peterson +Date: 14 January, 2001 + +Definitions: +============ + +In the following I will use the following definitions: + +1) A matrix is a mathematical object that represents a collection of + objects (elements), usually visualized in a table form, and one can + define a set of various (algebraic,etc) operations for matrices. + One can think of a matrix as a defintion of a certain mapping: + (i) |--> A(i) + where i belongs to the set of indices (an index itself can be a + sequence of objects, for example, a sequence of integers) and A(i) + is an element from a specified set, for example, a set of fruits. + Symbol A then denotes a matrix of fruits. + +2) An array is a storage object that represents a collection of + objects stored in a certain systematic way, for example, as an + ordered sequence in computer memory. + +In order to manipulate matrices using computers, one must store matrix +elements in computer memory. In the following, I will assume that the +elements of a matrix is stored as an array. There is no unique way in +which order one should save matrix elements in the array. However, in +C and Fortran programming languages, two, unfortunately different, +conventions are used. + +Aim: +==== + +The purpose of this writing is to work out an interface for Python +language so that C and Fortran routines can be called without +bothering about how multi-dimensional matrices are stored in memory. +For example, accessing a matrix element A[i,j] in Python will be +equivalent to accessing the same matrix in C, using A[i][j], or in +Fortran, using A(i,j). + +External conditions: +==================== + +In C programming language, it is custom to think that matrices are +stored in the so-called row-major order, that is, a matrix is stored +row by row, each row is as a contiguous array in computer memory. + +In Fortran programming language, matrices are stored in the +column-major order: each column is a contiguous array in computer +memory. + +In Python programming language, matrices can be stored using Python +Numeric array() function that uses internally C approach, that is, +elements of matrices are stored in row-major order. For example, +A = array([[1,2,3],[4,5,6]]) represents a 2-by-3 matrix + + / 1 2 3 \ + | | + \ 4 5 6 / + +and its elements are stored in computer memory as the following array: + + 1 2 3 4 5 6 + +The same matrix, if used in Fortran, would be stored in computer +memory as the following array: + + 1 4 2 5 3 6 + +Problem and solution: +===================== + +A problem arises if one wants to use the same matrix both in C and in +Fortran functions. Then the difference in storage order of a matrix +elements must be taken into account. This technical detail can be very +confusing even for an experienced programmer. This is because when +passing a matrix to a Fortran subroutine, you must (mentally or +programmically) transpose the matrix and when the subroutine returns, +you must transpose it back. + +As will be discussed below, there is a way to overcome these +difficulties in Python by creating an interface between Python and +Fortran code layers that takes care of this transition internally. So +that if you will read the manual pages of the Fortran codes, then you +need not to think about how matrices are actually stored, the storage +order will be the same, seemingly. + +Python / C / Fortran interface: +=============================== + +The interface between Python and Fortran codes will use the following +Python Numeric feature: transposing a Numeric array does not involve +copying of its data but just permuting the dimensions and strides of +the array (the so-called lazy transpose). + +However, when passing a Numeric array data pointer to Fortran or C +function, the data must be contiguous in memory. If it is not, then +data is rearranged inplace. I don't think that it can be avoided. +This is certainly a penalty hit to performance. However, one can +easily avoid it by creating a Numeric array with the right storage +order, so that after transposing, the array data will be contiguous in +memory and the data pointer can safely passed on to the Fortran +subroutine. This lazy-transpose operation will be done within the +interface and users need not to bother about this detail anymore (that +is, after they initialize Numeric array with matrix elements using the +proper order. Of course, the proper order depends on the target +function: C or Fortran). The interface should be smart enough to +minimize the need of real-transpose operations and the need to +additional memory storage as well. + +Statement of the problem: +========================= + +Consider a M-by-N matrix A of integers, where M and N are the number A +rows and columns, respectively. + +In Fortran language, the storing array of this matrix can be defined +as follows: + + integer A(M,N) + +in C: + + int A[M][N]; + +and in Python: + + A = Numeric.zeros((M,N),'i') + +Consider also the corresponding Fortran and C functions that +that use matrix arguments: + +Fortran: + subroutine FUN(A,M,N) + integer A(M,N) + ... + end +C: + void cun(int *a,int m,int n) { + ... + } + +and the corresponding Python interface signatures: + + def py_fun(a): + ... + def py_cun(a): + ... + +Main goal: +========== + +Our goal is to generate Python C/API functions py_fun and py_cun such +that their usage in Python would be identical. The cruical part of +their implementation are in functions that take a PyObject and +return a PyArrayObject such that it is contiguous and its data pointer +is suitable for passing on to the arguments of C or Fortran functions. +The prototypes of these functions are: + +PyArrayObject* fortran_array_from_pyobj( + int typecode, + int *dims, + int rank, + int intent, + PyObject *obj); + +and + +PyArrayObject* c_array_from_pyobj( + int typecode, + int *dims, + int rank, + int intent, + PyObject *obj); + +for wrapping Fortran and C functions, respectively. + +Pseudo-code for fortran_array_from_pyobj: +========================================= + +if type(obj) is ArrayType: + #raise not check(len(ravel(obj)) >= dims[0]*dims[1]*...*dims[rank-1]) + if obj.typecode is typecode: + if is_contiguous(obj): + transpose_data_inplace(obj) # real-transpose + set_transpose_strides(obj) # lazy-transpose + Py_INCREF(obj); + return obj + set_transpose_strides(obj) + if is_contiguous(obj): + set_transpose_strides(obj) + Py_INCREF(obj); + return obj + else: + tmp_obj = PyArray_ContiguousFromObject(obj,typecode,0,0) + swap_datapointer_and_typeinfo(obj,tmp_obj) + Py_DECREF(tmp_obj); + set_transpose_strides(obj) + Py_INCREF(obj); + return obj + else: + tmp_obj = PyArray_FromDims(rank,dims,typecode) + set_transpose_strides(tmp_obj) + if intent in [in,inout]: + copy_ND_array(obj,tmp_obj) + swap_datapointer_and_typeinfo(obj,tmp_obj) + Py_DECREF(tmp_obj); + Py_INCREF(obj); + return obj +elif obj is None: # happens when only intent is 'hide' + tmp_obj = PyArray_FromDims(rank,dims,typecode) + if intent is out: + set_transpose_strides(tmp_obj) + # otherwise tmp_obj->data is used as a work array + Py_INCREF(tmp_obj) + return tmp_obj +else: + tmp_obj = PyArray_ContiguousFromObject(obj,typecode,0,0) + #raise not check(len(ravel(obj)) >= dims[0]*dims[1]*...*dims[rank-1]) + set_transpose_strides(tmp_obj) + transpose_data_inplace(tmp_obj) + Py_INCREF(tmp_obj) + return tmp_obj + +Notes: + 1) CPU expensive tasks are in transpose_data_inplace and + copy_ND_array, PyArray_ContiguousFromObject. + 2) Memory expensive tasks are in PyArray_FromDims, + PyArray_ContiguousFromObject + 3) Side-effects are expected when set_transpose_strides and + transpose_data_inplace are used. For example: + >>> a = Numeric([[1,2,3],[4,5,6]],'d') + >>> a.is_contiguous() + 1 + >>> py_fun(a) + >>> a.typecode() + 'i' + >>> a.is_contiguous() + 0 + >>> transpose(a).is_contiguous() + 1 + +Pseudo-code for c_array_from_pyobj: +=================================== + +if type(obj) is ArrayType: + #raise not check(len(ravel(obj)) >= dims[0]*dims[1]*...*dims[rank-1]) + if obj.typecode is typecode: + if is_contiguous(obj): + Py_INCREF(obj); + return obj + else: + tmp_obj = PyArray_ContiguousFromObject(obj,typecode,0,0) + swap_datapointer_and_typeinfo(obj,tmp_obj) + Py_DECREF(tmp_obj); + Py_INCREF(obj); + return obj + else: + tmp_obj = PyArray_FromDims(rank,dims,typecode) + if intent in [in,inout]: + copy_ND_array(obj,tmp_obj) + swap_datapointer_and_typeinfo(obj,tmp_obj) + Py_DECREF(tmp_obj); + Py_INCREF(obj); + return obj +elif obj is None: # happens when only intent is 'hide' + tmp_obj = PyArray_FromDims(rank,dims,typecode) + Py_INCREF(tmp_obj) + return tmp_obj +else: + tmp_obj = PyArray_ContiguousFromObject(obj,typecode,0,0) + #raise not check(len(ravel(obj)) >= dims[0]*dims[1]*...*dims[rank-1]) + Py_INCREF(tmp_obj) + return tmp_obj + + +14 January, 2002 +Pearu Peterson <pearu@cens.ioc.ee>
\ No newline at end of file diff --git a/numpy/f2py/doc/multiarray/fun.pyf b/numpy/f2py/doc/multiarray/fun.pyf new file mode 100644 index 000000000..ed5d1923f --- /dev/null +++ b/numpy/f2py/doc/multiarray/fun.pyf @@ -0,0 +1,89 @@ +!%f90 -*- f90 -*- + +! Example: +! Using f2py for wrapping multi-dimensional Fortran and C arrays +! [NEW APPROACH, use it with f2py higher than 2.8.x] +! $Id: fun.pyf,v 1.3 2002/01/18 10:06:50 pearu Exp $ + +! Usage (with gcc compiler): +! f2py -c fun.pyf foo.f bar.c + +python module fun ! in + interface ! in :fun + +! >>> from Numeric import * +! >>> import fun +! >>> a=array([[1,2,3],[4,5,6]]) + + subroutine foo(a,m,n) ! in :fun:foo.f + integer dimension(m,n) :: a + intent(in,out,copy) :: a + integer optional,check(shape(a,0)==m),depend(a) :: m=shape(a,0) + integer optional,check(shape(a,1)==n),depend(a) :: n=shape(a,1) + end subroutine foo + +! >>> print fun.foo.__doc__ +! foo - Function signature: +! a = foo(a,[m,n]) +! Required arguments: +! a : input rank-2 array('i') with bounds (m,n) +! Optional arguments: +! m := shape(a,0) input int +! n := shape(a,1) input int +! Return objects: +! a : rank-2 array('i') with bounds (m,n) + +! >>> print fun.foo(a) +! F77: +! m= 2, n= 3 +! Row 1: +! a(i= 1,j= 1) = 1 +! a(i= 1,j= 2) = 2 +! a(i= 1,j= 3) = 3 +! Row 2: +! a(i= 2,j= 1) = 4 +! a(i= 2,j= 2) = 5 +! a(i= 2,j= 3) = 6 +! [[77777 2 3] +! [ 4 5 6]] + + + subroutine bar(a,m,n) + intent(c) + intent(c) bar + integer dimension(m,n) :: a + intent(in,out) :: a + integer optional,check(shape(a,0)==m),depend(a) :: m=shape(a,0) + integer optional,check(shape(a,1)==n),depend(a) :: n=shape(a,1) + intent(in) m,n + end subroutine bar + +! >>> print fun.bar.__doc__ +! bar - Function signature: +! a = bar(a,[m,n]) +! Required arguments: +! a : input rank-2 array('i') with bounds (m,n) +! Optional arguments: +! m := shape(a,0) input int +! n := shape(a,1) input int +! Return objects: +! a : rank-2 array('i') with bounds (m,n) + +! >>> print fun.bar(a) +! C:m=2, n=3 +! Row 1: +! a(i=0,j=0)=1 +! a(i=0,j=1)=2 +! a(i=0,j=2)=3 +! Row 2: +! a(i=1,j=0)=4 +! a(i=1,j=1)=5 +! a(i=1,j=2)=6 +! [[7777 2 3] +! [ 4 5 6]] + + end interface +end python module fun + +! This file was auto-generated with f2py (version:2.9.166). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/doc/multiarray/run.pyf b/numpy/f2py/doc/multiarray/run.pyf new file mode 100644 index 000000000..bb12a439b --- /dev/null +++ b/numpy/f2py/doc/multiarray/run.pyf @@ -0,0 +1,91 @@ +!%f90 -*- f90 -*- + +! Example: +! Using f2py for wrapping multi-dimensional Fortran and C arrays +! [OLD APPROACH, do not use it with f2py higher than 2.8.x] +! $Id: run.pyf,v 1.1 2002/01/14 15:49:46 pearu Exp $ + +! Usage (with gcc compiler): +! f2py -c run.pyf foo.f bar.c -DNO_APPEND_FORTRAN + +python module run ! in + interface ! in :run + +! >>> from Numeric import * +! >>> import run +! >>> a=array([[1,2,3],[4,5,6]],'i') + + subroutine foo(a,m,n) + fortranname foo_ + integer dimension(m,n) :: a + integer optional,check(shape(a,1)==m),depend(a) :: m=shape(a,1) + integer optional,check(shape(a,0)==n),depend(a) :: n=shape(a,0) + end subroutine foo + +! >>> print run.foo.__doc__ +! foo - Function signature: +! foo(a,[m,n]) +! Required arguments: +! a : input rank-2 array('i') with bounds (n,m) +! Optional arguments: +! m := shape(a,1) input int +! n := shape(a,0) input int + +! >>> run.foo(a) +! F77: +! m= 3, n= 2 +! Row 1: +! a(i= 1,j= 1) = 1 +! a(i= 1,j= 2) = 4 +! Row 2: +! a(i= 2,j= 1) = 2 +! a(i= 2,j= 2) = 5 +! Row 3: +! a(i= 3,j= 1) = 3 +! a(i= 3,j= 2) = 6 + +! >>> run.foo(transpose(a)) +! F77: +! m= 2, n= 3 +! Row 1: +! a(i= 1,j= 1) = 1 +! a(i= 1,j= 2) = 2 +! a(i= 1,j= 3) = 3 +! Row 2: +! a(i= 2,j= 1) = 4 +! a(i= 2,j= 2) = 5 +! a(i= 2,j= 3) = 6 + + subroutine bar(a,m,n) + intent(c) + integer dimension(m,n) :: a + integer optional,check(shape(a,0)==m),depend(a) :: m=shape(a,0) + integer optional,check(shape(a,1)==n),depend(a) :: n=shape(a,1) + end subroutine bar + +! >>> print run.bar.__doc__ +! bar - Function signature: +! bar(a,[m,n]) +! Required arguments: +! a : rank-2 array('i') with bounds (m,n) +! Optional arguments: +! m := shape(a,0) int +! n := shape(a,1) int + +! >>> run.bar(a) +! C:m=2, n=3 +! Row 1: +! a(i=0,j=0)=1 +! a(i=0,j=1)=2 +! a(i=0,j=2)=3 +! Row 2: +! a(i=1,j=0)=4 +! a(i=1,j=1)=5 +! a(i=1,j=2)=6 + + + end interface +end python module run + +! This file was auto-generated with f2py (version:2.8.172). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/doc/multiarray/transpose.txt b/numpy/f2py/doc/multiarray/transpose.txt new file mode 100644 index 000000000..a8d41e6df --- /dev/null +++ b/numpy/f2py/doc/multiarray/transpose.txt @@ -0,0 +1,1127 @@ +From: Phil Garner (garner@signal.dra.hmg.gb) + Subject: In place matrix transpose + Newsgroups: sci.math.num-analysis + Date: 1993-08-05 06:35:06 PST + + +Someone was talking about matrix transposes earlier on. It's a +curious subject. I found that an in-place transpose is about 12 times +slower than the trivial copying method. + +Here's somthing I nicked from netlib and translated into C to do the +in-place one for those that are interested: (matrix must be in one +block) + + +typedef float scalar; /* float -> double for double precision */ + +/* + * In Place Matrix Transpose + * From: Algorithm 380 collected algorithms from ACM. + * Converted to C by Phil Garner + * + * Algorithm appeared in comm. ACM, vol. 13, no. 05, + * p. 324. + */ +int trans(scalar *a, unsigned m, unsigned n, int *move, int iwrk) +{ + scalar b; + int i, j, k, i1, i2, ia, ib, ncount, kmi, Max, mn; + + /* + * a is a one-dimensional array of length mn=m*n, which + * contains the m by n matrix to be transposed. + * move is a one-dimensional array of length iwrk + * used to store information to speed up the process. the + * value iwrk=(m+n)/2 is recommended. Return val indicates the + * success or failure of the routine. + * normal return = 0 + * errors + * -2, iwrk negative or zero. + * ret > 0, (should never occur). in this case + * we set ret equal to the final value of i when the search + * is completed but some loops have not been moved. + * check arguments and initialise + */ + + /* Function Body */ + if (n < 2 || m < 2) + return 0; + if (iwrk < 1) + return -2; + + /* If matrix is square, exchange elements a(i,j) and a(j,i). */ + if (n == m) + { + for (i = 0; i < m - 1; ++i) + for (j = i + 1; j < m; ++j) + { + i1 = i + j * m; + i2 = j + i * m; + b = a[i1]; + a[i1] = a[i2]; + a[i2] = b; + } return 0; + } + + /* Non square matrix */ + ncount = 2; + for (i = 0; i < iwrk; ++i) + move[i] = 0; + + if (n > 2) + /* Count number,ncount, of single points. */ + for (ia = 1; ia < n - 1; ++ia) + { + ib = ia * (m - 1) / (n - 1); + if (ia * (m - 1) != ib * (n - 1)) + continue; + ++ncount; + i = ia * m + ib; + if (i > iwrk) + continue; + move[i] = 1; + } + + /* Set initial values for search. */ + mn = m * n; + k = mn - 1; + kmi = k - 1; + Max = mn; + i = 1; + + while (1) + { + /* Rearrange elements of a loop. */ + /* At least one loop must be re-arranged. */ + i1 = i; + while (1) + { + b = a[i1]; + while (1) + { + i2 = n * i1 - k * (i1 / m); + if (i1 <= iwrk) + move[i1 - 1] = 2; + ++ncount; + if (i2 == i || i2 >= kmi) + { + if (Max == kmi || i2 == i) + break; + Max = kmi; + } + a[i1] = a[i2]; + i1 = i2; + } + + /* Test for symmetric pair of loops. */ + a[i1] = b; + if (ncount >= mn) + return 0; + if (i2 == Max || Max == kmi) + break; + Max = kmi; + i1 = Max; + } + + /* Search for loops to be rearranged. */ + while (1) + { + Max = k - i; + ++i; + kmi = k - i; + if (i > Max) + return i; + if (i <= iwrk) + { + if (move[i-1] < 1) + break; + continue; + } + if (i == n * i - k * (i / m)) + continue; + i1 = i; + while (1) + { + i2 = n * i1 - k * (i1 / m); + if (i2 <= i || i2 >= Max) + break; + i1 = i2; + } + if (i2 == i) + break; + } + } /* End never reached */ +} + +-- + ,----------------------------- ______ + ____ | Phil Garner. \___| |/ \ \ ____ +/__/ `--, _L__L\_ | garner@signal.dra.hmg.gb | _|`---' \_/__/ `--, +`-0---0-' `-0--0-' `--OO-------------------O-----' `---0---' `-0---0-' + + From: Murray Dow (mld900@anusf.anu.edu.au) + Subject: Re: In place matrix transpose + Newsgroups: sci.math.num-analysis + Date: 1993-08-09 19:45:57 PST + + +In article <23qmp3INN3gl@mentor.dra.hmg.gb>, garner@signal.dra.hmg.gb (Phil Garner) writes: +|> Someone was talking about matrix transposes earlier on. It's a +|> curious subject. I found that an in-place transpose is about 12 times +|> slower than the trivial copying method. +|> + +Algorithm 380 from CACM is sloweer than ALG 467. Here are my times +from a VP2200 vector computer. Note that the CACM algorithms are scalar. +Times are in seconds, for a 900*904 matrix: + +380 NAG 467 disc copy +1.03 1.14 .391 .177 + +Compare two vector algortihms, one I wrote and the second a matrix +copy: + +My Alg Matrix copy +.0095 .0097 + +Conclusions: dont use Alg 380 from Netlib. If you have the available memory, +do a matrix copy. If you don't have the memory, I will send you my algorithm +when I have published it. +-- +Murray Dow GPO Box 4 Canberra ACT 2601 Australia +Supercomputer Facility Phone: +61 6 2495028 +Australian National University Fax: +61 6 2473425 +mld900@anusf.anu.edu.au + +============================================================================= + +From: Mark Smotherman (mark@hubcap.clemson.edu) + Subject: Matrix transpose benchmark [was Re: MIPS R8000 == TFP?] + Newsgroups: comp.arch, comp.benchmarks, comp.sys.super + Date: 1994-07-01 06:35:51 PST + + +mccalpin@perelandra.cms.udel.edu (John D. McCalpin) writes: + +> +>Of course, these results are all for the naive algorithm. I would be +>interested to see what an efficient blocked algorithm looks like. +>Anyone care to offer one? There is clearly a lot of performance +>to be gained by the effort.... + +Here is a matrix transpose benchmark generator. Enter something like + + 10d10eij; + +and you get a benchmark program with tiles of size 10 for the i and j +inner loops. Please email code improvements and flames. + +Enjoy! + + +/*--------------------------------------------------------------------------- + + Matrix Transpose Generator + + Copyright 1993, Dept. of Computer Science, Clemson University + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appears in all copies. + + Clemson University and its Dept. of Computer Science make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied warranty. + + Original author: Mark Smotherman + + -------------------------------------------------------------------------*/ + + +/* tpgen.c version 1.0 + * + * generate a matrix transpose loop nest, with tiling and unrolling + * (timing code using getrusage is included in the generated program) + * + * mark smotherman + * mark@cs.clemson.edu + * clemson university + * 9 july 1993 + * + * a loop nest can be described by the order of its loop indices, so + * this program takes as input a simple language describing these indices: + * <number>d ==> generate tiling loop for index i with step size of <number> + * <number>e ==> generate tiling loop for index j with step size of <number> + * <number>i ==> generate loop for index i with unrolling factor of <number> + * <number>j ==> generate loop for index j with unrolling factor of <number> + * ; ==> input terminator (required) + * rules are: + * i,j tokens must appear + * if d appears, it must appear before i + * if e appears, it must appear before j + * ; must appear + * matrix size is controlled by #define N in this program. + * + * this code was adapted from mmgen.c v1.2 and extended to generate pre- + * condition loops for unrolling factors that do not evenly divide the + * matrix size (or the tiling step size for loop nests with a tiling loop). + * note that this program only provides a preconditioning loop for the + * innermost loop. unrolling factors for non-innermost loops that do not + * evenly divide the matrix size (or step size) are not supported. + * + * my interest in this program generator is to hook it to a sentence + * generator and a minimum execution time finder, that is + * while((sentence=sgen())!=NULL){ + * genprogram=tpgen(sentence); + * system("cc -O4 genprogram.c"); + * system("a.out >> tpresults"); + * } + * findmintime(tpresults); + * this will find the optimum algorithm for the host system via an + * exhaustive search. + * + * please report bugs and suggestions for enhancements to me. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#define N 500 + +#define ALLOC1 temp1=(struct line *)malloc(sizeof(struct line));\ +temp1->indentcnt=indentcnt; + +#define LINK1 temp1->next=insertbefore;\ +insertafter->next=temp1;\ +insertafter=temp1; + +#define INSERT1 temp1->next=start;\ +start=temp1; + +#define ALLOC2 temp1=(struct line *)malloc(sizeof(struct line));\ +temp2=(struct line *)malloc(sizeof(struct line));\ +temp1->indentcnt=indentcnt;\ +temp2->indentcnt=indentcnt++; + +#define LINK2 temp1->next=temp2;\ +temp2->next=insertbefore;\ +insertafter->next=temp1;\ +insertafter=temp1;\ +insertbefore=temp2; + +struct line{ int indentcnt; char line[256]; struct line *next; }; + +int indentcnt; +int iflag,jflag; +int ijflag,jiflag; +int dflag,eflag; +int counter; +int iistep,jjstep; +int iunroll,junroll; +int precond; + +char c; +int i,ttp,nt; +char *p0; +char tptype[80]; +char number[10]; + +struct line *start,*head,*insertafter,*insertbefore,*temp1,*temp2; + +void processloop(); +void processstmt(); + +main(){ + + indentcnt=0; + iflag=jflag=0; + ijflag=jiflag=0; + dflag=eflag=0; + iunroll=junroll=0; + counter=1; + precond=0; + ttp=0; + + start=NULL; + ALLOC2 + sprintf(temp1->line,"/* begin */\nt_start=second();\n"); + sprintf(temp2->line,"/* end */\nt_end = second();\n"); + head=temp1; temp1->next=temp2; temp2->next=NULL; + insertafter=temp1; insertbefore=temp2; + + while((c=getchar())!=';'){ + tptype[ttp++]=c; + if(isdigit(c)){ + nt=0; + while(isdigit(c)){ + number[nt++]=c; + c=getchar(); + if(c==';'){ fprintf(stderr,"unexpected ;!\n"); exit(1); } + tptype[ttp++]=c; + } + number[nt]='\0'; + sscanf(number,"%d",&counter); + } + switch(c){ + case 'd': + if(iflag){ fprintf(stderr,"d cannot appear after i!\n"); exit(1); } + dflag++; + ALLOC1 + sprintf(temp1->line,"#define IISTEP %d\n",counter); + INSERT1 + iistep=counter; + counter=1; + ALLOC2 + sprintf(temp1->line,"for(ii=0;ii<%d;ii+=IISTEP){\n",N); + sprintf(temp2->line,"}\n",N); + LINK2 + ALLOC1 + sprintf(temp1->line,"it=min(ii+IISTEP,%d);\n",N); + LINK1 + break; + case 'e': + if(jflag){ fprintf(stderr,"e cannot appear after j!\n"); exit(1); } + eflag++; + ALLOC1 + sprintf(temp1->line,"#define JJSTEP %d\n",counter); + INSERT1 + jjstep=counter; + counter=1; + ALLOC2 + sprintf(temp1->line,"for(jj=0;jj<%d;jj+=JJSTEP){\n",N); + sprintf(temp2->line,"}\n",N); + LINK2 + ALLOC1 + sprintf(temp1->line,"jt=min(jj+JJSTEP,%d);\n",N); + LINK1 + break; + case 'i': + iunroll=counter; + counter=1; + iflag++; if(jflag) jiflag++; + if(dflag) precond=iistep%iunroll; else precond=N%iunroll; + if(precond&&(jiflag==0)){ + fprintf(stderr,"unrolling factor for outer loop i\n"); + fprintf(stderr," does not evenly divide matrix/step size!\n"); + exit(1); + } + if(dflag&&(iunroll>1)&&(N%iistep)){ + fprintf(stderr,"with unrolling of i, step size for tiled loop ii\n"); + fprintf(stderr," does not evenly divide matrix size!\n"); + exit(1); + } + processloop('i',dflag,iunroll,precond,junroll); + break; + case 'j': + junroll=counter; + counter=1; + jflag++; if(iflag) ijflag++; + if(eflag) precond=jjstep%junroll; else precond=N%junroll; + if(precond&&(ijflag==0)){ + fprintf(stderr,"unrolling factor for outer loop j\n"); + fprintf(stderr," does not evenly divide matrix/step size!\n"); + exit(1); + } + if(eflag&&(junroll>1)&&(N%jjstep)){ + fprintf(stderr,"with unrolling of j, step size for tiled loop jj\n"); + fprintf(stderr," does not evenly divide matrix size!\n"); + exit(1); + } + processloop('j',eflag,junroll,precond,iunroll); + break; + default: break; + } + } + processstmt(); + + tptype[ttp++]=c; + + if((iflag==0)||(jflag==0)){ + fprintf(stderr, + "one of the loops (i,j) was not specified!\n"); + exit(1); + } + + temp1=start; + while(temp1!=NULL){ + printf("%s",temp1->line); + temp1=temp1->next; + } + printf("#include <stdio.h>\n"); + printf("#include <sys/time.h>\n"); + printf("#include <sys/resource.h>\n"); + if(dflag|eflag) printf("#define min(a,b) ((a)<=(b)?(a):(b))\n"); + printf("double second();\n"); + printf("double t_start,t_end,t_total;\n"); + printf("int times;\n"); + printf("\ndouble b[%d][%d],dummy[10000],bt[%d][%d];\n\nmain(){\n" + ,N,N,N,N); + if(precond) printf(" int i,j,n;\n"); else printf(" int i,j;\n"); + if(dflag) printf(" int ii,it;\n"); + if(eflag) printf(" int jj,jt;\n"); + printf("/* set coefficients so that result matrix should have \n"); + printf(" * column entries equal to column index\n"); + printf(" */\n"); + printf(" for (i=0;i<%d;i++){\n",N); + printf(" for (j=0;j<%d;j++){\n",N); + printf(" b[i][j] = (double) i;\n"); + printf(" }\n"); + printf(" }\n"); + printf("\n t_total=0.0;\n for(times=0;times<10;times++){\n\n",N); + printf("/* try to flush cache */\n"); + printf(" for(i=0;i<10000;i++){\n",N); + printf(" dummy[i] = 0.0;\n"); + printf(" }\n"); + printf("%s",head->line); + temp1=head->next; + while(temp1!=NULL){ + for(i=0;i<temp1->indentcnt;i++) printf(" "); + while((p0=strstr(temp1->line,"+0"))!=NULL){ + *p0++=' '; *p0=' '; + } + printf("%s",temp1->line); + temp1=temp1->next; + } + printf("\n t_total+=t_end-t_start;\n }\n"); + printf("/* check result */\n"); + printf(" for (j=0;j<%d;j++){\n",N); + printf(" for (i=0;i<%d;i++){\n",N); + printf(" if (bt[i][j]!=((double)j)){\n"); + printf(" fprintf(stderr,\"error in bt[%cd][%cd]",'%','%'); + printf("\\n\",i,j);\n"); + printf(" fprintf(stderr,\" for %s\\n\");\n",tptype); + printf(" exit(1);\n"); + printf(" }\n"); + printf(" }\n"); + printf(" }\n"); + tptype[ttp]='\0'; + printf(" printf(\"%c10.2f secs\",t_total);\n",'%'); + printf(" printf(\" for 10 runs of %s\\n\");\n",tptype); + printf("}\n"); + printf("double second(){\n"); + printf(" void getrusage();\n"); + printf(" struct rusage ru;\n"); + printf(" double t;\n"); + printf(" getrusage(RUSAGE_SELF,&ru);\n"); + printf(" t = ((double)ru.ru_utime.tv_sec) +\n"); + printf(" ((double)ru.ru_utime.tv_usec)/1.0e6;\n"); + printf(" return t;\n"); + printf("}\n"); + +} + +void processloop(index,flag,unroll,precond,unroll2) +char index; +int flag,unroll,precond,unroll2; +{ + char build[80],temp[40]; + int n; + if(precond){ + ALLOC1 + sprintf(temp1->line,"/* preconditioning loop for unrolling factor */\n"); + LINK1 + if(unroll2==1){ + build[0]='\0'; + if(flag){ + if(index='i') + sprintf(temp,"n=IISTEP%c%d; ",'%',unroll); + else + sprintf(temp,"n=JJSTEP%c%d; ",'%',unroll); + strcat(build,temp); + sprintf(temp,"for(%c=%c%c;%c<%c%c+n;%c++) ",index,index,index, + index,index,index,index); + strcat(build,temp); + }else{ + sprintf(temp,"n=%d%c%d; ",N,'%',unroll); + strcat(build,temp); + sprintf(temp,"for(%c=0;%c<n;%c++) ",index,index,index); + strcat(build,temp); + } + sprintf(temp,"bt[i][j]=b[j][i];\n"); + strcat(build,temp); + ALLOC1 + sprintf(temp1->line,"%s\n",build); + LINK1 + }else{ + if(flag){ + ALLOC1 + if(index=='i') + sprintf(temp1->line,"n=IISTEP%c%d;\n",'%',unroll); + else + sprintf(temp1->line,"n=JJSTEP%c%d;\n",'%',unroll); + LINK1 + ALLOC1 + sprintf(temp1->line,"for(%c=%c%c;%c<%c%c+n;%c++){\n",index,index,index, + index,index,index,index); + LINK1 + }else{ + ALLOC1 + sprintf(temp1->line,"n=%d%c%d;\n",N,'%',unroll); + LINK1 + ALLOC1 + sprintf(temp1->line,"for(%c=0;%c<n;%c++){\n",index,index,index); + LINK1 + } + if(index=='i'){ + for(n=0;n<unroll2;n++){ + ALLOC1 + sprintf(temp1->line," bt[i][j+%d]=b[j+%d][i];\n",n,n); + LINK1 + } + }else{ + for(n=0;n<unroll2;n++){ + ALLOC1 + sprintf(temp1->line," bt[i+%d][j]=b[j][i+%d];\n",n,n); + LINK1 + } + } + ALLOC1 + sprintf(temp1->line,"}\n"); + LINK1 + } + ALLOC2 + if(flag){ + sprintf(temp1->line,"for(%c=%c%c+n;%c<%ct;%c+=%d){\n",index,index,index, + index,index,index,unroll); + }else{ + sprintf(temp1->line,"for(%c=n;%c<%d;%c+=%d){\n",index,index,N,index, + unroll); + } + sprintf(temp2->line,"}\n",N); + LINK2 + }else{ + ALLOC2 + if(unroll==1){ + if(flag){ + sprintf(temp1->line,"for(%c=%c%c;%c<%ct;%c++){\n",index,index,index, + index,index,index); + }else{ + sprintf(temp1->line,"for(%c=0;%c<%d;%c++){\n",index,index,N,index); + } + }else{ + if(flag){ + sprintf(temp1->line,"for(%c=%c%c;%c<%ct;%c+=%d){\n",index,index,index, + index,index,index,unroll); + }else{ + sprintf(temp1->line,"for(%c=0;%c<%d;%c+=%d){\n",index,index,N,index, + unroll); + } + } + sprintf(temp2->line,"}\n",N); + LINK2 + } +} + +void processstmt() +{ + int i,j; + for(i=0;i<iunroll;i++){ + for(j=0;j<junroll;j++){ + ALLOC1 + sprintf(temp1->line,"bt[i+%d][j+%d]=b[j+%d][i+%d];\n",i,j,j,i); + LINK1 + } + } +} +-- +Mark Smotherman, Computer Science Dept., Clemson University, Clemson, SC + +======================================================================= +From: has (h.genceli@bre.com) + Subject: transpose of a nxm matrix stored in a vector !!! + Newsgroups: sci.math.num-analysis + Date: 2000/07/25 + + +If I have a matrix nrows x ncols, I can store it in a vector. +so A(i,j) is really a[i*ncols+j]. So really TRANS of A +(say B) is really is also a vector B where + +0<=i b[j*nrows+i] <nrows, 0<=j<ncols +b[j*nrows+i] = a[i*ncols+j]. + +Fine but I want to use only one array a to do this transformation. + +i.e a[j*nrows+i] = a[i*ncols+j]. this will itself +erase some elements so each time a swap is necessary in a loop. + +temp = a[j*nrows+i] +a[j*nrows+i] = a[i*ncols+j] +a[i*ncols+j] = temp + +but still this will lose some info as it is, so indexing +should have more intelligence in it ???? anybody +can give me a lead here, thanks. + +Has + + From: wei-choon ng (wng@ux8.cso.uiuc.edu) + Subject: Re: transpose of a nxm matrix stored in a vector !!! + Newsgroups: sci.math.num-analysis + Date: 2000/07/25 + + +has <h.genceli@bre.com> wrote: +> If I have a matrix nrows x ncols, I can store it in a vector. +> so A(i,j) is really a[i*ncols+j]. So really TRANS of A +> (say B) is really is also a vector B where + +[snip] + +Hey, if you just want to do a transpose-matrix vector multiply, there is +no need to explicitly store the transpose matrix in another array and +doubling the storage! + +W.C. +-- + + From: Robin Becker (robin@jessikat.fsnet.co.uk) + Subject: Re: transpose of a nxm matrix stored in a vector !!! + Newsgroups: sci.math.num-analysis + Date: 2000/07/25 + + +In article <snr532fo3j1180@corp.supernews.com>, has <h.genceli@bre.com> +writes +>If I have a matrix nrows x ncols, I can store it in a vector. +>so A(i,j) is really a[i*ncols+j]. So really TRANS of A +>(say B) is really is also a vector B where +> +>0<=i b[j*nrows+i] <nrows, 0<=j<ncols +>b[j*nrows+i] = a[i*ncols+j]. +> +>Fine but I want to use only one array a to do this transformation. +> +>i.e a[j*nrows+i] = a[i*ncols+j]. this will itself +>erase some elements so each time a swap is necessary in a loop. +> +>temp = a[j*nrows+i] +>a[j*nrows+i] = a[i*ncols+j] +>a[i*ncols+j] = temp +> +>but still this will lose some info as it is, so indexing +>should have more intelligence in it ???? anybody +>can give me a lead here, thanks. +> +>Has +> +> +> + +void dmx_transpose(unsigned n, unsigned m, double* a, double* b) +{ + unsigned size = m*n; + if(b!=a){ + real *bmn, *aij, *anm; + bmn = b + size; /*b+n*m*/ + anm = a + size; + while(b<bmn) for(aij=a++;aij<anm; aij+=n ) *b++ = *aij; + } + else if(size>3){ + unsigned i,row,column,current; + for(i=1, size -= 2;i<size;i++){ + current = i; + do { + /*current = row+n*column*/ + column = current/m; + row = current%m; + current = n*row + column; + } while(current < i); + + if (current >i) { + real temp = a[i]; + a[i] = a[current]; + a[current] = temp; + } + } + } +} +-- +Robin Becker + + From: E. Robert Tisdale (edwin@netwood.net) + Subject: Re: transpose of a nxm matrix stored in a vector !!! + Newsgroups: sci.math.num-analysis + Date: 2000/07/25 + + +Take a look at +The C++ Scalar, Vector, Matrix and Tensor class library + + http://www.netwood.net/~edwin/svmt/ + +<Type><System>SubVector& + <Type><System>SubVector::transpose(Extent p, Extent q) { + <Type><System>SubVector& + v = *this; + if (1 < p && 1 < q) { + // A vector v of extent n = qp is viewed as a q by p matrix U and + // a p by q matrix V where U_{ij} = v_{p*i+j} and V_{ij} = v_{q*i+j}. + // The vector v is modified in-place so that V is the transpose of U. + // The algorithm searches for every sequence k_s of S indices + // such that a circular shift of elements v_{k_s} <-- v_{k_{s+1}} + // and v_{k_{S-1}} <-- v_{k_0} effects an in-place transpose. + Extent n = q*p; + Extent m = 0; // count up to n-2 + Offset l = 0; // 1 <= l <= n-2 + while (++l < n-1 && m < n-2) { + Offset k = l; + Offset j = k; + while (l < (k = (j%p)*q + j/p)) { // Search backward for k < l. + j = k; + } + // If a sequence of indices beginning with l has any index k < l, + // it has already been transposed. The sequence length S = 1 + // and diagonal element v_k is its own transpose if k = j. + // Skip every index sequence that has already been transposed. + if (k == l) { // a new sequence + if (k < j) { // with 1 < S + TYPE x = v[k]; // save v_{k_0} + do { + v[k] = v[j]; // v_{k_{s}} <-- v_{k_{s+1}} + k = j; + ++m; + } while (l < (j = (k%q)*p + k/q)); + v[k] = x; // v_{k_{S-1}} <-- v_{k_0} + } + ++m; + } + } + } return v; + } + + + +<Type><System>SubVector& + +Read the rest of this message... (50 more lines) + + From: Victor Eijkhout (eijkhout@disco.cs.utk.edu) + Subject: Re: transpose of a nxm matrix stored in a vector !!! + Newsgroups: sci.math.num-analysis + Date: 2000/07/25 + + +"Alan Miller" <amiller @ vic.bigpond.net.au> writes: + +> The attached routine does an in situ transpose. +> begin 666 Dtip.f90 +> M4U5"4D]55$E.12!D=&EP("AA+"!N,2P@;C(L(&YD:6TI#0HA("TM+2TM+2TM + +Hm. F90? You're not silently allocating a temporary I hope? + +(Why did you have to encode this? Now I have to save, this decode, ... +and all for plain ascii?) + +-- +Victor Eijkhout +"When I was coming up, [..] we knew exactly who the they were. It was us +versus them, and it was clear who the them was were. Today, we are not +so sure who the they are, but we know they're there." [G.W. Bush] + + From: Alan Miller (amiller_@_vic.bigpond.net.au) + Subject: Re: transpose of a nxm matrix stored in a vector !!! + Newsgroups: sci.math.num-analysis + Date: 2000/07/25 + + +Victor Eijkhout wrote in message ... +>"Alan Miller" <amiller @ vic.bigpond.net.au> writes: +> +>> The attached routine does an in situ transpose. +>> begin 666 Dtip.f90 +>> M4U5"4D]55$E.12!D=&EP("AA+"!N,2P@;C(L(&YD:6TI#0HA("TM+2TM+2TM +> +>Hm. F90? You're not silently allocating a temporary I hope? +> +>(Why did you have to encode this? Now I have to save, this decode, ... +>and all for plain ascii?) +> + +I know the problem. +I sometimes use a Unix system, and have to use decode64 to read +attachments. On the other hand, Windows wraps lines around, +formats then and generally makes the code unreadable. + +The straight code for dtip (double transpose in place) is attached +this time. + +>-- +>Victor Eijkhout + + +-- +Alan Miller, Retired Scientist (Statistician) +CSIRO Mathematical & Information Sciences +Alan.Miller -at- vic.cmis.csiro.au +http://www.ozemail.com.au/~milleraj +http://users.bigpond.net.au/amiller/ + + +================================================================= + +From: Darran Edmundson (dedmunds@sfu.ca) + Subject: array reordering algorithm? + Newsgroups: sci.math.num-analysis + Date: 1995/04/30 + + +A code I've written refers to a complex array as two separate real arrays. +However, I have a canned subroutine which expects a single array where the +real and imaginary values alternate. Essentially I have a case of mismatched +data structures, yet for reasons that I'd rather not go into, I'm stuck with them. + +Assuming that the two real arrays A and B are sequential in memory, and +that the single array of alternating real/imaginary values C shares the same +space, what I need is a porting subroutine that remaps the data from one format +to the other - using as little space as possible. + +I think of the problem as follows. Imagine an array of dimension 10 containing +the values 1,3,5,7,9,2,4,6,8,10 in this order. + + A(1) / 1 \ C(1) + A(2) | 3 | C(2) + A(3) | 5 | C(3) + A(4) | 7 | C(4) + A(5) \ 9 | C(5) + | + B(1) / 2 | C(6) + B(2) | 4 | C(7) + B(3) | 6 | C(8) + B(4) | 8 | C(9) + B(5) \ 10 / C(10) + +Given that I know this initial pattern, I want to sort the array C in-place *without +making comparisons*. That is, the algorithm can only depend on the initial +knowledge of the pattern. Do you see what a sort is going to do? It will +make the A and B arrays alternate, i.e. C(1)=A(1), C(2)=B(1), C(3)=A(2), +C(4)=B(2), etc. It's not a real sort though because I can't actually refer to the +values above (i.e. no comparisons) because A and B will be holding real data, +not this contrived pattern. The pattern above exists though - it's the +natural ordering in memory of A and B. + +Either pair swapping only or a small amount of workspace can be used. The +in-place is important - imagine scaling this problem up to an +array of 32 or 64 million double precision values and you can easily see how +duplicating the array is not a feasible solution. + +Any ideas? I've been stumped on this for a day and a half now. + +Darran Edmundson +dedmunds@sfu.ca + + From: Roger Critchlow (rec@elf115.elf.org) + Subject: Re: array reordering algorithm? + Newsgroups: sci.math.num-analysis + Date: 1995/04/30 + + + Any ideas? I've been stumped on this for a day and a half now. + +Here's some code for in situ permutations of arrays that I wrote +a few years ago. It all started from the in situ transposition +algorithms in the Collected Algorithms of the ACM, the references +for which always get lost during the decryption from fortran. + +This is the minimum space algorithm. All you need to supply is +a function which computes the new order array index from the old +order array index. + +If you can spare n*m bits to record the indexes of elements which +have been permuted, then you can speed things up. + +-- rec -- + +------------------------------------------------------------------------ +/* +** Arbitrary in situ permutations of an m by n array of base type TYPE. +** Copyright 1995 by Roger E Critchlow Jr, rec@elf.org, San Francisco, CA. +** Fair use permitted, caveat emptor. +*/ +typedef int TYPE; + +int transposition(int ij, int m, int n) /* transposition about diagonal from upper left to lower right */ +{ return ((ij%m)*n+ (ij/m)); } + +int countertrans(int ij, int m, int n) /* transposition about diagonal from upper right to lower left */ +{ return ((m-1-(ij%m))*n+ (n-1-(ij/m))); } + +int rotate90cw(int ij, int m, int n) /* 90 degree clockwise rotation */ +{ return ((m-1-(ij%m))*n+ (ij/m)); } + +int rotate90ccw(int ij, int m, int n) /* 90 degree counter clockwise rotation */ +{ return ((ij%m)*n+ (n-1-(ij/m))); } + +int rotate180(int ij, int m, int n) /* 180 degree rotation */ +{ return ((m-1-(ij/n))*n+ (n-1-(ij%n))); } + +int reflecth(int ij, int m, int n) /* reflection across horizontal plane */ +{ return ((m-1-(ij/n))*n+ (ij%n)); } + +int reflectv(int ij, int m, int n) /* reflection across vertical plane */ +{ return ((ij/n)*n+ (n-1-(ij%n))); } + +int in_situ_permutation(TYPE a[], int m, int n, int (*origination)(int ij, int m, int n)) +{ + int ij, oij, dij, n_to_do; + TYPE b; + n_to_do = m*n; + for (ij = 0; ij < m*n && n_to_do > 0; ij += 1) { + /* Test for previously permuted */ + for (oij = origination(ij,m,n); oij > ij; oij = origination(oij,m,n)) + ; + if (oij < ij) + continue; + /* Chase the cycle */ + dij = ij; + b = a[ij]; + for (oij = origination(dij,m,n); oij != ij; oij = origination(dij,m,n)) { + a[dij] = a[oij]; + dij = oij; + n_to_do -= 1; + } + a[dij] = b; + n_to_do -= 1; + } return 0; +} + +#define TESTING 1 +#if TESTING + +/* fill a matrix with sequential numbers, row major ordering */ +void fill_matrix_rows(a, m, n) TYPE *a; int m, n; +{ + int i, j; + for (i = 0; i < m; i += 1) + for (j = 0; j < n; j += 1) + a[i*n+j] = i*n+j; +} + +/* fill a matrix with sequential numbers, column major ordering */ +void fill_matrix_cols(a, m, n) TYPE *a; int m, n; +{ + int i, j; + for (i = 0; i < m; i += 1) + for (j = 0; j < n; j += 1) + a[i*n+j] = j*m+i; +} + +/* test a matrix for sequential numbers, row major ordering */ +int test_matrix_rows(a, m, n) TYPE *a; int m, n; +{ + int i, j, o; + for (o = i = 0; i < m; i += 1) + for (j = 0; j < n; j += 1) + o += a[i*n+j] != i*n+j; + return o; +} + +/* test a matrix for sequential numbers, column major ordering */ +int test_matrix_cols(a, m, n) TYPE *a; int m, n; +{ + int i, j, o; + for (o = i = 0; i < m; i += 1) + for (j = 0; j < n; j += 1) + o += a[i*n+j] != j*m+i; + return o; +} + +/* print a matrix */ +void print_matrix(a, m, n) TYPE *a; int m, n; +{ + char *format; + int i, j; + if (m*n < 10) format = "%2d"; + if (m*n < 100) format = "%3d"; + if (m*n < 1000) format = "%4d"; + if (m*n < 10000) format = "%5d"; + for (i = 0; i < m; i += 1) { + for (j = 0; j < n; j += 1) + printf(format, a[i*n+j]); + printf("\n"); + } +} + +#if TEST_TRANSPOSE +#define MAXSIZE 1000 + +main() +{ + int i, j, m, n, o; + TYPE a[MAXSIZE]; + for (m = 1; m < sizeof(a)/sizeof(a[0]); m += 1) + for (n = 1; m*n < sizeof(a)/sizeof(a[0]); n += 1) { + fill_matrix_rows(a, m, n); /* {0 1} {2 3} */ + if (o = transpose(a, m, n)) + printf(">> transpose returned %d for a[%d][%d], row major\n", o, m, n); + if ((o = test_matrix_cols(a, n, m)) != 0) /* {0 2} {1 3} */ + printf(">> transpose made %d mistakes for a[%d][%d], row major\n", o, m, n); + /* column major */ + fill_matrix_rows(a, m, n); + if (o = transpose(a, m, n)) + printf(">> transpose returned %d for a[%d][%d], column major\n", o, m, n); + if ((o = test_matrix_cols(a, n, m)) != 0) + printf(">> transpose made %d mistakes for a[%d][%d], column major\n", o, m, n); + } return 0; +} +#endif /* TEST_TRANSPOSE */ + + +#define TEST_DISPLAY 1 +#if TEST_DISPLAY +main(argc, argv) int argc; char *argv[]; +{ + TYPE *a; + int m = 5, n = 5; + extern void *malloc(); + if (argc > 1) { + m = atoi(argv[1]); + if (argc > 2) + n = atoi(argv[2]); + } + a = malloc(m*n*sizeof(TYPE)); + + printf("matrix\n"); + fill_matrix_rows(a, m, n); + print_matrix(a, m, n); + printf("transposition\n"); + in_situ_permutation(a, m, n, transposition); + print_matrix(a, n, m); + + printf("counter transposition\n"); + fill_matrix_rows(a, m, n); + in_situ_permutation(a, m, n, countertrans); + print_matrix(a, n, m); + + printf("rotate 90 degrees clockwise\n"); + fill_matrix_rows(a, m, n); + in_situ_permutation(a, m, n, rotate90cw); + print_matrix(a, n, m); + + printf("rotate 90 degrees counterclockwise\n"); + fill_matrix_rows(a, m, n); + in_situ_permutation(a, m, n, rotate90ccw); + print_matrix(a, n, m); + + printf("rotate 180 degrees\n"); + fill_matrix_rows(a, m, n); + in_situ_permutation(a, m, n, rotate180); + print_matrix(a, m, n); + + printf("reflect across horizontal\n"); + fill_matrix_rows(a, m, n); + in_situ_permutation(a, m, n, reflecth); + print_matrix(a, m, n); + + printf("reflect across vertical\n"); + fill_matrix_rows(a, m, n); + in_situ_permutation(a, m, n, reflectv); + print_matrix(a, m, n); + + return 0; +} + +#endif +#endif + diff --git a/numpy/f2py/doc/multiarrays.txt b/numpy/f2py/doc/multiarrays.txt new file mode 100644 index 000000000..704208976 --- /dev/null +++ b/numpy/f2py/doc/multiarrays.txt @@ -0,0 +1,120 @@ +From pearu@ioc.ee Thu Dec 30 09:58:01 1999 +Date: Fri, 26 Nov 1999 12:02:42 +0200 (EET) +From: Pearu Peterson <pearu@ioc.ee> +To: Users of f2py2e -- Curtis Jensen <cjensen@be-research.ucsd.edu>, + Vladimir Janku <vjanku@kvet.sk>, + Travis Oliphant <Oliphant.Travis@mayo.edu> +Subject: Multidimensional arrays in f2py2e + + +Hi! + +Below I will describe how f2py2e wraps Fortran multidimensional arrays as +it constantly causes confusion. As for example, consider Fortran code + + subroutine foo(l,m,n,a) + integer l,m,n + real*8 a(l,m,n) + .. + end +Running f2py2e with -h flag, it generates the following signature + +subroutine foo(l,m,n,a) + integer optional,check(shape(a,2)==l),depend(a) :: l=shape(a,2) + integer optional,check(shape(a,1)==m),depend(a) :: m=shape(a,1) + integer optional,check(shape(a,0)==n),depend(a) :: n=shape(a,0) + real*8 dimension(l,m,n),check(rank(a)==3) :: a +end subroutine foo + +where parameters l,m,n are considered optional and they are initialized in +Python C/API code using the array a. Note that a can be also a proper +list, that is, asarray(a) should result in a rank-3 array. But then there +is an automatic restriction that elements of a (in Python) are not +changeable (in place) even if Fortran subroutine changes the array a (in +C,Fortran). + +Hint: you can attribute the array a with 'intent(out)' which causes foo to +return the array a (in Python) if you are to lazy to define a=asarray(a) +before the call to foo (in Python). + +Calling f2py2e without the switch -h, a Python C/API module will be +generated. After compiling it and importing it to Python +>>> print foo.__doc__ +shows +None = foo(a,l=shape(a,2),m=shape(a,1),n=shape(a,0)) + +You will notice that f2py2e has changed the order of arguments putting the +optional ones at the end of the argument list. +Now, you have to be careful when specifying the parameters l,m,n (though +situations where you need this should be rare). A proper definition +of the array a should be, say + + a = zeros(n,m,l) + +Note that the dimensions l,m,n are in reverse, that is, the array a should +be transposed when feeding it to the wrapper. + +Hint (and a performance hit): To be always consistent with fortran +arrays, you can define, for example + a = zeros(l,m,n) +and call from Python + foo(transpose(a),l,m,n) +which is equivalent with the given Fortran call + call foo(l,m,n,a) + +Another hint (not recommended, though): If you don't like optional +arguments feature at all and want to be strictly consistent with Fortran +signature, that is, you want to call foo from Python as + foo(l,m,n,a) +then you should edit the signature to +subroutine foo(l,m,n,a) + integer :: l + integer :: m + integer :: n + real*8 dimension(l,m,n),check(rank(a)==3),depend(l,m,n), & + check(shape(a,2)==l,shape(a,1)==m,shape(a,0)==n):: a +end +Important! Note that now the array a should depend on l,m,n +so that the checks can be performed in the proper order. +(you cannot check, say, shape(a,2)==l before initializing a or l) +(There are other ways to edit the signature in order to get the same +effect but they are not so safe and I will not discuss about them here). + +Hint: If the array a should be a work array (as used frequently in +Fortran) and you a too lazy (its good lazyness;) to provide it (in Python) +then you can define it as optional by ediding the signature: +subroutine foo(l,m,n,a) + integer :: l + integer :: m + integer :: n + real*8 dimension(l,m,n),check(rank(a)==3),depend(l,m,n), & + check(shape(a,2)==l,shape(a,1)==m,shape(a,0)==n):: a + optional a +end +Note again that the array a must depend on l,m,n. Then the array a will be +allocated in the Python C/API module. Not also that +>>> print foo.__doc__ +shows then +None = foo(l,m,n,a=) +Performance hint: If you call the given foo lots of times from Python then +you don't want to allocate/deallocate the memory in each call. So, it is +then recommended to define a temporary array in Python, for instance +>>> tmp = zeros(n,m,l) +>>> for i in ...: +>>> foo(l,m,n,a=tmp) + +Important! It is not good at all to define + >>> tmp = transpose(zeros(l,m,n)) +because tmp will be then a noncontiguous array and there will be a +huge performance hit as in Python C/API a new array will be allocated and +also a copying of arrays will be performed elementwise! +But + >>> tmp = asarray(transpose(zeros(l,m,n))) +is still ok. + +I hope that the above answers lots of your (possible) questions about +wrapping Fortran multidimensional arrays with f2py2e. + +Regards, + Pearu + diff --git a/numpy/f2py/doc/notes.tex b/numpy/f2py/doc/notes.tex new file mode 100644 index 000000000..2746b049d --- /dev/null +++ b/numpy/f2py/doc/notes.tex @@ -0,0 +1,310 @@ + +\section{Calling wrapper functions from Python} +\label{sec:notes} + +\subsection{Scalar arguments} +\label{sec:scalars} + +In general, for scalar argument you can pass in in +addition to ordinary Python scalars (like integers, floats, complex +values) also arbitrary sequence objects (lists, arrays, strings) --- +then the first element of a sequence is passed in to the Fortran routine. + +It is recommended that you always pass in scalars of required type. This +ensures the correctness as no type-casting is needed. +However, no exception is raised if type-casting would produce +inaccurate or incorrect results! For example, in place of an expected +complex value you can give an integer, or vice-versa (in the latter case only +a rounded real part of the complex value will be used). + +If the argument is \texttt{intent(inout)} then Fortran routine can change the +value ``in place'' only if you pass in a sequence object, for +instance, rank-0 array. Also make sure that the type of an array is of +correct type. Otherwise type-casting will be performed and you may +get inaccurate or incorrect results. The following example illustrates this +\begin{verbatim} +>>> a = array(0) +>>> calculate_pi(a) +>>> print a +3 +\end{verbatim} + +If you pass in an ordinary Python scalar in place of +\texttt{intent(inout)} variable, it will be used as an input argument +since +Python +scalars cannot not be changed ``in place'' (all Python scalars +are immutable objects). + +\subsection{String arguments} +\label{sec:strings} + +You can pass in strings of arbitrary length. If the length is greater than +required, only a required part of the string is used. If the length +is smaller than required, additional memory is allocated and fulfilled +with `\texttt{\bs0}'s. + +Because Python strings are immutable, \texttt{intent(inout)} argument +expects an array version of a string --- an array of chars: +\texttt{array("<string>")}. +Otherwise, the change ``in place'' has no effect. + + +\subsection{Array arguments} +\label{sec:arrays} + +If the size of an array is relatively large, it is \emph{highly + recommended} that you pass in arrays of required type. Otherwise, +type-casting will be performed which includes the creation of new +arrays and their copying. If the argument is also +\texttt{intent(inout)}, the wasted time is doubled. So, pass in arrays +of required type! + +On the other hand, there are situations where it is perfectly all +right to ignore this recommendation: if the size of an array is +relatively small or the actual time spent in Fortran routine takes +much longer than copying an array. Anyway, if you want to optimize +your Python code, start using arrays of required types. + +Another source of performance hit is when you use non-contiguous +arrays. The performance hit will be exactly the same as when using +incorrect array types. This is because a contiguous copy is created +to be passed in to the Fortran routine. + +\fpy provides a feature such that the ranks of array arguments need +not to match --- only the correct total size matters. For example, if +the wrapper function expects a rank-1 array \texttt{array([...])}, +then it is correct to pass in rank-2 (or higher) arrays +\texttt{array([[...],...,[...]])} assuming that the sizes will match. +This is especially useful when the arrays should contain only one +element (size is 1). Then you can pass in arrays \texttt{array(0)}, +\texttt{array([0])}, \texttt{array([[0]])}, etc and all cases are +handled correctly. In this case it is correct to pass in a Python +scalar in place of an array (but then ``change in place'' is ignored, +of course). + +\subsubsection{Multidimensional arrays} + +If you are using rank-2 or higher rank arrays, you must always +remember that indexing in Fortran starts from the lowest dimension +while in Python (and in C) the indexing starts from the highest +dimension (though some compilers have switches to change this). As a +result, if you pass in a 2-dimensional array then the Fortran routine +sees it as the transposed version of the array (in multi-dimensional +case the indexes are reversed). + +You must take this matter into account also when modifying the +signature file and interpreting the generated Python signatures: + +\begin{itemize} +\item First, when initializing an array using \texttt{init\_expr}, the index +vector \texttt{\_i[]} changes accordingly to Fortran convention. +\item Second, the result of CPP-macro \texttt{shape(<array>,0)} + corresponds to the last dimension of the Fortran array, etc. +\end{itemize} +Let me illustrate this with the following example:\\ +\begin{verbatim} +! Fortran file: arr.f + subroutine arr(l,m,n,a) + integer l,m,n + real*8 a(l,m,n) + ... + end +\end{verbatim} +\fpy will generate the following signature file:\\ +\begin{verbatim} +!%f90 +! Signature file: arr.f90 +python module arr ! in + interface ! in :arr + subroutine arr(l,m,n,a) ! in :arr:arr.f + integer optional,check(shape(a,2)==l),depend(a) :: l=shape(a,2) + integer optional,check(shape(a,1)==m),depend(a) :: m=shape(a,1) + integer optional,check(shape(a,0)==n),depend(a) :: n=shape(a,0) + real*8 dimension(l,m,n) :: a + end subroutine arr + end interface +end python module arr +\end{verbatim} +and the following wrapper function will be produced +\begin{verbatim} +None = arr(a,l=shape(a,2),m=shape(a,1),n=shape(a,0)) +\end{verbatim} + +In general, I would suggest not to specify the given optional +variables \texttt{l,m,n} when calling the wrapper function --- let the +interface find the values of the variables \texttt{l,m,n}. But there +are occasions when you need to specify the dimensions in Python. + +So, in Python a proper way to create an array from the given +dimensions is +\begin{verbatim} +>>> a = zeros(n,m,l,'d') +\end{verbatim} +(note that the dimensions are reversed and correct type is specified), +and then a complete call to \texttt{arr} is +\begin{verbatim} +>>> arr(a,l,m,n) +\end{verbatim} + +From the performance point of view, always be consistent with Fortran +indexing convention, that is, use transposed arrays. But if you do the +following +\begin{verbatim} +>>> a = transpose(zeros(l,m,n,'d')) +>>> arr(a) +\end{verbatim} +then you will get a performance hit! The reason is that here the +transposition is not actually performed. Instead, the array \texttt{a} +will be non-contiguous which means that before calling a Fortran +routine, internally a contiguous array is created which +includes memory allocation and copying. In addition, if +the argument array is also \texttt{intent(inout)}, the results are +copied back to the initial array which doubles the +performance hit! + +So, to improve the performance: always pass in +arrays that are contiguous. + +\subsubsection{Work arrays} + +Often Fortran routines use the so-called work arrays. The +corresponding arguments can be declared as optional arguments, but be +sure that all dimensions are specified (bounded) and defined before +the initialization (dependence relations). + +On the other hand, if you call the Fortran routine many times then you +don't want to allocate/deallocate the memory of the work arrays on +every call. In this case it is recommended that you create temporary +arrays with proper sizes in Python and use them as work arrays. But be +careful when specifying the required type and be sure that the +temporary arrays are contiguous. Otherwise the performance hit would +be even harder than the hit when not using the temporary arrays from +Python! + + + +\subsection{Call-back arguments} +\label{sec:cbargs} + +\fpy builds a very flexible call-back mechanisms for call-back +arguments. If the wrapper function expects a call-back function \texttt{fun} +with the following Python signature to be passed in +\begin{verbatim} +def fun(a_1,...,a_n): + ... + return x_1,...,x_k +\end{verbatim} +but the user passes in a function \texttt{gun} with the signature +\begin{verbatim} +def gun(b_1,...,b_m): + ... + return y_1,...,y_l +\end{verbatim} +and the following extra arguments (specified as additional optional +argument for the wrapper function): +\begin{verbatim} +fun_extra_args = (e_1,...,e_p) +\end{verbatim} +then the actual call-back is constructed accordingly to the following rules: +\begin{itemize} +\item if \texttt{p==0} then \texttt{gun(a\_1,...,a\_q)}, where + \texttt{q=min(m,n)}; +\item if \texttt{n+p<=m} then \texttt{gun(a\_1,...,a\_n,e\_1,...,e\_p)}; +\item if \texttt{p<=m<n+p} then \texttt{gun(a\_1,...,a\_q,e\_1,...,e\_p)}, + where \texttt{q=m-p}; +\item if \texttt{p>m} then \texttt{gun(e\_1,...,e\_m)}; +\item if \texttt{n+p} is less than the number of required arguments + of the function \texttt{gun}, an exception is raised. +\end{itemize} + +A call-back function \texttt{gun} may return any number of objects as a tuple: +if \texttt{k<l}, then objects \texttt{y\_k+1,...,y\_l} are ignored; +if \texttt{k>l}, then only objects \texttt{x\_1,...,x\_l} are set. + + +\subsection{Obtaining information on wrapper functions} +\label{sec:info} + +From the previous sections we learned that it is useful for the +performance to pass in arguments of expected type, if possible. To +know what are the expected types, \fpy generates a complete +documentation strings for all wrapper functions. You can read them +from Python by printing out \texttt{\_\_doc\_\_} attributes of the +wrapper functions. For the example in Sec.~\ref{sec:intro}: +\begin{verbatim} +>>> print foobar.foo.__doc__ +Function signature: + foo(a) +Required arguments: + a : in/output rank-0 array(int,'i') +>>> print foobar.bar.__doc__ +Function signature: + bar = bar(a,b) +Required arguments: + a : input int + b : input int +Return objects: + bar : int +\end{verbatim} + +In addition, \fpy generates a LaTeX document +(\texttt{<modulename>module.tex}) containing a bit more information on +the wrapper functions. See for example Appendix that contains a result +of the documentation generation for the example module +\texttt{foobar}. Here the file \texttt{foobar-smart.f90} (modified +version of \texttt{foobar.f90}) is used --- it contains +\texttt{note(<LaTeX text>)} attributes for specifying some additional +information. + +\subsection{Wrappers for common blocks} +\label{sec:wrapcomblock} + +[See examples \texttt{test-site/e/runme*}] + +What follows is obsolute for \fpy version higher that 2.264. + +\fpy generates wrapper functions for common blocks. For every common +block with a name \texttt{<commonname>} a function +\texttt{get\_<commonname>()} is constructed that takes no arguments +and returns a dictionary. The dictionary represents maps between the +names of common block fields and the arrays containing the common +block fields (multi-dimensional arrays are transposed). So, in order +to access to the common block fields, you must first obtain the +references +\begin{verbatim} +commonblock = get_<commonname>() +\end{verbatim} +and then the fields are available through the arrays +\texttt{commonblock["<fieldname>"]}. +To change the values of common block fields, you can use for scalars +\begin{verbatim} +commonblock["<fieldname>"][0] = <new value> +\end{verbatim} +and for arrays +\begin{verbatim} +commonblock["<fieldname>"][:] = <new array> +\end{verbatim} +for example. + +For more information on the particular common block wrapping, see +\texttt{get\_<commonname>.\_\_doc\_\_}. + +\subsection{Wrappers for F90/95 module data and routines} +\label{sec:wrapf90modules} + +[See example \texttt{test-site/mod/runme\_mod}] + +\subsection{Examples} +\label{sec:examples} + +Examples on various aspects of wrapping Fortran routines to Python can +be found in directories \texttt{test-site/d/} and +\texttt{test-site/e/}: study the shell scripts \texttt{runme\_*}. See +also files in \texttt{doc/ex1/}. + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: diff --git a/numpy/f2py/doc/oldnews.html b/numpy/f2py/doc/oldnews.html new file mode 100644 index 000000000..914265bbe --- /dev/null +++ b/numpy/f2py/doc/oldnews.html @@ -0,0 +1,121 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> +<HTML> +<HEAD> +<META name="Author" content="Pearu Peterson"> +<!-- You may add here some keywords (comma separeted list) --> +<META name="Keywords" content="fortran,python,interface,f2py,f2py2e,wrapper,fpig"> +<TITLE>F2PY - Fortran to Python Interface Generator</TITLE> +<LINK rel="stylesheet" type="text/css" href="/styles/userstyle.css"> +</HEAD> + +<body> +<h2><a href="http://cens.ioc.ee/projects/f2py2e">F2PY</a> old news.</h2> + +<dl> + <dt> February 23, 2002 + <dd> Fixed a bug of incorrect shapes of multi-dimensional arrays + when returning from Fortran routine (thanks to Eric for pointing + this out). + <code>F2PY_REPORT_ATEXIT</code> is disabled by default under Win32. + <dt> February 14, 2002 + <dd> Introduced <code>callprotoargument</code> statement so that + proper prototypes can be specified (this fixes SEGFAULTs when + wrapping C functions with <code>f2py</code>, see <a + href="NEWS.txt">NEWS.txt</a> for more details). Updated for the + latest <code>scipy_distutils</code>. Fixed few bugs. + <dt> February 3, 2002 + <dd> Introduced <code>intent(overwrite),intent(out=name)</code> + attributes, <code>callstatement C-expr;</code> statement, and + reviewed reference counting in callback mechanism. Fixed bugs. + <dt> January 18, 2002 + <dd> Introduced extra keyword argument <code>copy_#varname#=1</code> + for <code>intent(copy)</code> variables, + <code>-DF2PY_REPORT_ATEXIT</code> for reporting <code>f2py</code> + performance, + <code>has_column_major_storage</code> member function for generated + modules, and <a href="http://dmalloc.com/">dmalloc</a> support. + <dt> January 16, 2002 + <dd> BREAKING NEWS! Solved long lasted dilemma of wrapping + multi-dimensional arrays where different + storage orders in C and Fortran come into account. From now on + this difference is dealt automatically by the f2py generated + module and in a very efficient way. For example, the corresponding + element A(i,j) of a Fortran array can be accessed in Python as + A[i,j]. + <dt> January 13, 2002 + <dd> Fifth Public Release is coming soon..., a snapshot is available + for download, now with updates. + <dt> December 17, 2001 + <dd> <a href="Release-4.x.txt">Fourth Public Release</a>: Win32 support. + <dd> Making <code>f2py2e</code> a module. Currently it has only one + member function <code>run_main(comline_list)</code>. + <dd> Removed command line arguments <code>-fix,-f90,-f77</code> + and introduced many new ones. See <a href="NEWS.txt">NEWS.txt</a>. + <dd> <code>intent(..)</code> statement with empty name list defines + default <code>intent(..)</code> attribute for all routine arguments. + <dd> Refinements in Win32 support. Eric Jones has provided a f2py + HOWTO for Windows users. See <a href="win32_notes.txt">win32_notes.txt</a>. + <dd> Major rewrote of the code generator to achieve + a higher quality of generated C/API modules (-Wall messages are + considerably reduced, especially for callback functions). + <dd> Many bugs were fixed. + <dt> December 12, 2001 + <dd> Win32 support (thanks to Eric Jones and Tiffany Kamm). Minor + cleanups and fixes. + <dt> December 4, 2001 + <dd> <a href="Release-3.x.txt">Third Public Release</a>: <code>f2py</code> supports <code>distutils</code>. It can be + installed with one and it generates <code>setup_modulename.py</code> + to be used for building Python extension modules. + <dd> Introduced <code>threadsafe</code>, <code>fortranname</code>, + and <code>intent(c)</code> statements. + <dt> August 13, 2001 + <dd> Changed the name FPIG to F2PY for avoiding confusion with project names. + <dd> Updated <code>f2py</code> for use with Numeric version 20.x. + <dt> January 12, 2001 + <dd> Example usages of <a href="pyfobj.html"><code>PyFortranObject</code></a>. + Fixed bugs. Updated the + <a href="f2python9.html">Python 9 Conference paper</a> (F2PY paper). + <dt> December 9, 2000 + <dd> Implemented support for <code>PARAMETER</code> statement. + <dt> November 6, 2000 + <dd> Submitted a paper for 9th Python Conference (accepted). It is available in <a + href="f2python9.html">html</a>, <a href="f2python9.pdf">PDF</a>, + and <a href="f2python9.ps.gz">Gzipped PS</a> formats. + <dt> September 17, 2000 + <dd> Support for F90/95 module data and routines. COMMON block + wrapping is rewritten. New signature file syntax: + <code>pythonmodule</code>. Signature files generated with + f2py-2.264 or earlier, are incompatible (need replacement + <code>module</code> with + <code>pythonmodule</code>). + <dt> September 12, 2000 + <dd> The second public release of <code>f2py</code> is out. See <a + href="Release-2.x.txt">Release notes</a>. + <dt> September 11, 2000 + <dd> Now <code>f2py</code> supports wrapping Fortran 90/95 module routines + (support for F90/95 module data coming soon) + <dt> June 12, 2000 + <dd> Now <code>f2py</code> has a mailing list <a +href="#f2py-users">f2py-users</a> open for discussion. + +</dl> + + +<!-- End of user text --> +<HR> +<ADDRESS> +<A href="http://validator.w3.org/"><IMG border=0 align=right src="/icons/vh40.gif" alt="Valid HTML 4.0!" height=31 width=88></A> +<A href="http://cens.ioc.ee/~pearu/" target="_top">Pearu Peterson</A> +<A href="mailto:pearu (at) ioc.ee"><pearu(at)ioc.ee></A><BR> +<!-- hhmts start --> +Last modified: Mon Dec 3 19:40:26 EET 2001 +<!-- hhmts end --> +</ADDRESS> +<!-- You may want to comment the following line out when the document is final--> +<!-- Check that the reference is right --> +<!--A href="http://validator.w3.org/check?uri=http://cens.ioc.ee/projects/f2py2e/index.html;ss"> Submit this page for validation</A--> + +</BODY> + + +</HTML> diff --git a/numpy/f2py/doc/options.tex b/numpy/f2py/doc/options.tex new file mode 100644 index 000000000..84d9410f8 --- /dev/null +++ b/numpy/f2py/doc/options.tex @@ -0,0 +1,63 @@ + +\section{\fpy command line options} +\label{sec:opts} + +\fpy has the following command line syntax (run \fpy without arguments +to get up to date options!!!): +\begin{verbatim} +f2py [<options>] <fortran files> [[[only:]||[skip:]] <fortran functions> ]\ + [: <fortran files> ...] +\end{verbatim} +where +\begin{description} +\item[\texttt{<options>}] --- the following options are available: + \begin{description} + \item[\texttt{-f77}] --- \texttt{<fortran files>} are in Fortran~77 + fixed format (default). + \item[\texttt{-f90}] --- \texttt{<fortran files>} are in + Fortran~90/95 free format (default for signature files). + \item[\texttt{-fix}] --- \texttt{<fortran files>} are in + Fortran~90/95 fixed format. + \item[\texttt{-h <filename>}] --- after scanning the + \texttt{<fortran files>} write the signatures of Fortran routines + to file \texttt{<filename>} and exit. If \texttt{<filename>} + exists, \fpy quits without overwriting the file. Use + \texttt{-{}-overwrite-signature} to overwrite. + \item[\texttt{-m <modulename>}] --- specify the name of the module + when scanning Fortran~77 codes for the first time. \fpy will + generate Python C/API module source \texttt{<modulename>module.c}. + \item[\texttt{-{}-lower/-{}-no-lower}] --- lower/do not lower the cases + when scanning the \texttt{<fortran files>}. Default when + \texttt{-h} flag is specified/unspecified (that is for Fortran~77 + codes/signature files). + \item[\texttt{-{}-short-latex}] --- use this flag when you want to + include the generated LaTeX document to another LaTeX document. + \item[\texttt{-{}-debug-capi}] --- create a very verbose C/API + code. Useful for debbuging. +% \item[\texttt{-{}-h-force}] --- if \texttt{-h <filename>} is used then +% overwrite the file \texttt{<filename>} (if it exists) and continue +% with constructing the C/API module source. + \item[\texttt{-makefile <options>}] --- run \fpy without arguments + for more information. + \item[\texttt{-{}-use-libs}] --- see \texttt{-makefile}. + \item[\texttt{-{}-overwrite-makefile}] --- overwrite existing + \texttt{Makefile-<modulename>}. + \item[\texttt{-v}] --- print \fpy version number and exit. + \item[\texttt{-pyinc}] --- print Python include path and exit. + \end{description} +\item[\texttt{<fortran files>}] --- are the paths to Fortran files or + to signature files that will be scanned for \texttt{<fortran + functions>} in order to determine their signatures. +\item[\texttt{<fortran functons>}] --- are the names of Fortran + routines for which Python C/API wrapper functions will be generated. + Default is all that are found in \texttt{<fortran files>}. +\item[\texttt{only:}/\texttt{skip:}] --- are flags for filtering + in/out the names of fortran routines to be wrapped. Run \fpy without + arguments for more information about the usage of these flags. +\end{description} + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: diff --git a/numpy/f2py/doc/python9.tex b/numpy/f2py/doc/python9.tex new file mode 100644 index 000000000..cda3cd18b --- /dev/null +++ b/numpy/f2py/doc/python9.tex @@ -0,0 +1,1046 @@ +\documentclass[twocolumn]{article}
+\usepackage{epsfig}
+\usepackage{xspace}
+\usepackage{verbatim}
+
+
+\headsep=0pt
+\topmargin=0pt
+\headheight=0pt
+\oddsidemargin=0pt
+\textwidth=6.5in
+\textheight=9in
+%%tth:\newcommand{\xspace}{ }
+\newcommand{\fpy}{\texttt{f2py}\xspace}
+\newcommand{\bs}{\symbol{`\\}}
+% need bs here:
+%%tth:\newcommand{\bs}{\texttt{<backslash>}}
+
+\newcommand{\tthhide}[1]{#1}
+\newcommand{\latexhide}[1]{}
+%%tth:\newcommand{\tthhide}[1]{}
+%%tth:\newcommand{\latexhide}[1]{#1}
+
+\newcommand{\shell}[1]{
+\latexhide{
+ \special{html:
+<BLOCKQUOTE>
+<pre>
+sh> #1
+</pre>
+</BLOCKQUOTE>}
+}
+\tthhide{
+ \\[1ex]
+ \hspace*{1em}
+ \texttt{sh> \begin{minipage}[t]{0.8\textwidth}#1\end{minipage}}\\[1ex]
+}
+}
+
+\newcommand{\email}[1]{\special{html:<A href="mailto:#1">}\texttt{<#1>}\special{html:</A>}}
+\newcommand{\wwwsite}[1]{\special{html:<A href="#1">}{#1}\special{html:</A>}}
+\title{Fortran to Python Interface Generator with
+an Application to Aerospace Engineering}
+\author{
+\large Pearu Peterson\\
+\small \email{pearu@cens.ioc.ee}\\
+\small Center of Nonlinear Studies\\
+\small Institute of Cybernetics at TTU\\
+\small Akadeemia Rd 21, 12618 Tallinn, ESTONIA\\[2ex]
+\large Joaquim R. R. A. Martins and Juan J. Alonso\\
+\small \email{joaquim.martins@stanford.edu}, \email{jjalonso@stanford.edu}\\
+\small Department of Aeronautics and Astronautics\\
+\small Stanford University, CA
+}
+\date{$Revision: 1.17 $\\\today}
+\begin{document}
+
+\maketitle
+
+\special{html: Other formats of this document:
+<A href=f2python9.ps.gz>Gzipped PS</A>,
+<A href=f2python9.pdf>PDF</A>
+}
+
+\begin{abstract}
+ FPIG --- Fortran to Python Interface Generator --- is a tool for
+ generating Python C/API extension modules that interface
+ Fortran~77/90/95 codes with Python. This tool automates the process
+ of interface generation by scanning the Fortran source code to
+ determine the signatures of Fortran routines and creating a
+ Python C/API module that contains the corresponding interface
+ functions. FPIG also attempts to find dependence relations between
+ the arguments of a Fortran routine call (e.g. an array and its
+ dimensions) and constructs interface functions with potentially
+ fewer arguments. The tool is extremely flexible since the user has
+ control over the generation process of the interface by specifying the
+ desired function signatures. The home page for FPIG can be found at
+ \wwwsite{http://cens.ioc.ee/projects/f2py2e/}.
+
+ FPIG has been used successfully to wrap a large number of Fortran
+ programs and libraries. Advances in computational science have led
+ to large improvements in the modeling of physical systems which are
+ often a result of the coupling of a variety of physical models that
+ were typically run in isolation. Since a majority of the available
+ physical models have been previously written in Fortran, the
+ importance of FPIG in accomplishing these couplings cannot be
+ understated. In this paper, we present an application of FPIG to
+ create an object-oriented framework for aero-structural analysis and
+ design of aircraft.
+\end{abstract}
+
+%%tth:
+\tableofcontents
+
+\section{Preface}
+\label{sec:preface}
+
+The use of high-performance computing has made it possible to tackle
+many important problems and discover new physical phenomena in science
+and engineering. These accomplishments would not have been achieved
+without the computer's ability to process large amounts of data in a
+reasonably short time. It can safely be said that the computer has
+become an essential tool for scientists and engineers. However, the
+diversity of problems in science and engineering has left its mark as
+computer programs have been developed in different programming
+languages, including languages developed to describe certain specific
+classes of problems.
+
+In interdisciplinary fields it is not uncommon for scientists and
+engineers to face problems that have already been solved in a
+different programming environment from the one they are familiar with.
+Unfortunately, researchers may not have the time or willingness to
+learn a new programming language and typically end up developing the
+corresponding tools in the language that they normally use. This
+approach to the development of new software can substantially impact
+the time to develop and the quality of the resulting product: firstly,
+it usually takes longer to develop and test a new tool than to learn a
+new programming environment, and secondly it is very unlikely that a
+non-specialist in a given field can produce a program that is more
+efficient than more established tools.
+
+To avoid situations such as the one described above, one alternative
+would be to provide automatic or semi-automatic interfaces between programming
+languages. Another possibility would be to provide language
+translators, but these obviously require more work than interface
+generators --- a translator must understand all language constructs
+while an interface generator only needs to understand a subset of these
+constructs. With an automatic interface between two languages, scientists or
+engineers can effectively use programs written in other programming
+languages without ever having to learn them.
+
+Although it is clear that it is impossible to interface arbitrary programming
+languages with each other, there is no reason for doing so. Low-level languages such as C and Fortran are well known for
+their speed and are therefore suitable for applications where
+performance is critical. High-level scripting languages, on the other
+hand, are generally slower but much easier to learn and use,
+especially when performing interactive analysis. Therefore, it makes
+sense to create interfaces only in one direction: from lower-level
+languages to higher-level languages.
+
+In an ideal world, scientists and engineers would use higher-level
+languages for the manipulation of the mathematical formulas in a problem
+rather than having to struggle with tedious programming details. For tasks
+that are computationally demanding, they would use interfaces to
+high-performance routines that are written in a lower-level language
+optimized for execution speed.
+
+
+\section{Introduction}
+\label{sec:intro}
+
+This paper presents a tool that has been developed for the creation of
+interfaces between Fortran and Python.
+
+
+The Fortran language is popular in
+scientific computing, and is used mostly in applications that use
+extensive matrix manipulations (e.g. linear algebra). Since Fortran
+ has been the standard language among scientists and engineers for
+ at least three decades, there is a large number of legacy codes available that
+ perform a variety of tasks using very sophisticated algorithms (see
+e.g. \cite{netlib}).
+
+The Python language \cite{python}, on the other hand, is a relatively
+new programming language. It is a very high-level scripting language
+that supports object-oriented programming. What makes Python
+especially appealing is its very clear and natural syntax, which makes it
+easy to learn and use. With Python one can implement relatively
+complicated algorithms and tasks in a short time with very compact
+source code.
+
+Although there are ongoing projects for extending Python's usage in
+scientific computation, it lacks reliable tools that are common in
+scientific and engineering such as ODE integrators, equation solvers,
+tools for FEM, etc. The implementation of all of these tools in Python
+would be not only too time-consuming but also inefficient. On the
+other hand, these tools are already developed in other,
+computationally more efficient languages such as Fortran or C.
+Therefore, the perfect role for Python in the context of scientific
+computing would be that of a ``gluing'' language. That is, the role
+of providing high-level interfaces to C, C++ and Fortran libraries.
+
+There are a number of widely-used tools that can be used for interfacing
+software libraries to Python. For binding C libraries with various
+scripting languages, including Python, the tool most often used is
+SWIG \cite{swig}. Wrapping Fortran routines with Python is less
+popular, mainly because there are many platform and compiler-specific
+issues that need to be addressed. Nevertheless, there is great
+interest in interfacing Fortran libraries because they provide
+invaluable tools for scientific computing. At LLNL, for example, a tool
+called PyFort has been developed for connecting Fortran and
+Python~\cite{pyfort}.
+
+The tools mentioned above require an input file describing signatures
+of functions to be interfaced. To create these input files, one needs
+to have a good knowledge of either C or Fortran. In addition,
+binding libraries that have thousands of routines can certainly constitute a
+very tedious task, even with these tools.
+
+The tool that is introduced in this paper, FPIG (Fortran to Python
+Interface Generator)~\cite{fpig}, automatically generates interfaces
+between Fortran and Python. It is different from the tools mentioned
+above in that FPIG can create signature files automatically by
+scanning the source code of the libraries and then construct Python
+C/API extension modules. Note that the user need not be experienced
+in C or even Fortran. In addition, FPIG is designed to wrap large
+Fortran libraries containing many routines with only one or two
+commands. This process is very flexible since one can always modify
+the generated signature files to insert additional attributes in order
+to achieve more sophisticated interface functions such as taking care
+of optional arguments, predicting the sizes of array arguments and
+performing various checks on the correctness of the input arguments.
+
+The organization of this paper is as follows. First, a simple example
+of FPIG usage is given. Then FPIG's basic features are described and
+solutions to platform and compiler specific issues are discussed.
+Unsolved problems and future work on FPIG's development are also
+addressed. Finally, an application to a large aero-structural solver
+is presented as real-world example of FPIG's usage.
+
+\section{Getting Started}
+\label{sec:getstart}
+
+To get acquainted with FPIG, let us consider the simple Fortran~77
+subroutine shown in Fig. \ref{fig:exp1.f}.
+\begin{figure}[htb]
+ \latexhide{\label{fig:exp1.f}}
+ \special{html:<BLOCKQUOTE>}
+ \verbatiminput{examples/exp1.f}
+ \special{html:</BLOCKQUOTE>}
+ \caption{Example Fortran code \texttt{exp1.f}. This routine calculates
+ the simplest rational lower and upper approximations to $e$ (for
+ details of
+ the algorithm see \cite{graham-etal}, p.122)}
+ \tthhide{\label{fig:exp1.f}}
+\end{figure}
+In the sections that follow, two ways of creating interfaces to this
+Fortran subroutine are described. The first and simplest way is
+suitable for Fortran codes that are developed in connection with \fpy.
+The second and not much more difficult method, is suitable for
+interfacing existing Fortran libraries which might have been developed
+by other programmers.
+
+Numerical Python~\cite{numpy} is needed in order to compile extension
+modules generated by FPIG.
+
+\subsection{Interfacing Simple Routines}
+\label{sec:example1}
+
+In order to call the Fortran routine \texttt{exp1} from Python, let us
+create an interface to it by using \fpy (FPIG's front-end program). In
+order to do this, we issue the following command, \shell{f2py -m foo
+exp1.f} where the option \texttt{-m foo} sets the name of the Python
+C/API extension module that \fpy will create to
+\texttt{foo}. To learn more about the \fpy command line options, run \fpy
+without arguments.
+
+The output messages in Fig. \ref{fig:f2pyoutmess}
+illustrate the procedure followed by \fpy:
+ (i) it scans the Fortran source code specified in the command line,
+ (ii) it analyses and determines the routine signatures,
+ (iii) it constructs the corresponding Python C/API extension modules,
+ (iv) it writes documentation to a LaTeX file, and
+ (v) it creates a GNU Makefile for building the shared modules.
+\begin{figure}[htb]
+ \latexhide{\label{fig:f2pyoutmess}}
+ \special{html:<BLOCKQUOTE>}
+ {\tthhide{\small}
+ \verbatiminput{examples/exp1mess.txt}
+ }
+ \special{html:</BLOCKQUOTE>}
+ \caption{Output messages of \texttt{f2py -m foo exp1.f}.}
+ \tthhide{\label{fig:f2pyoutmess}}
+\end{figure}
+
+Now we can build the \texttt{foo} module:
+\shell{make -f Makefile-foo}
+
+Figure \ref{fig:exp1session} illustrates a sample session for
+ calling the Fortran routine \texttt{exp1} from Python.
+\begin{figure}[htb]
+ \latexhide{\label{fig:exp1session}}
+ \special{html:<BLOCKQUOTE>}
+ \verbatiminput{examples/exp1session.txt}
+ \special{html:</BLOCKQUOTE>}
+ \caption{Calling Fortran routine \texttt{exp1} from Python. Here
+ \texttt{l[0]/l[1]} gives an estimate to $e$ with absolute error
+ less than \texttt{u[0]/u[1]-l[0]/l[1]} (this value may depend on
+ the platform and compiler used).}
+ \tthhide{\label{fig:exp1session}}
+\end{figure}
+
+Note the difference between the signatures of the Fortran routine
+\texttt{exp1(l,u,n)} and the corresponding wrapper function
+\texttt{l,u=exp1([n])}. Clearly, the later is more informative to
+the user: \texttt{exp1} takes one optional argument \texttt{n} and it
+returns \texttt{l}, \texttt{u}. This exchange of signatures is
+achieved by special comment lines (starting with \texttt{Cf2py}) in
+the Fortran source code --- these lines are interpreted by \fpy as
+normal Fortran code. Therefore, in the given example the line \texttt{Cf2py
+ integer*4 :: n = 1} informs \fpy that the variable \texttt{n} is
+optional with a default value equal to one. The line \texttt{Cf2py
+ intent(out) l,u} informs \fpy that the variables \texttt{l,u} are to be
+returned to Python after calling Fortran function \texttt{exp1}.
+
+\subsection{Interfacing Libraries}
+\label{sec:example2}
+
+In our example the Fortran source \texttt{exp1.f} contains \fpy
+specific information, though only as comments. When interfacing
+libraries from other parties, it is not recommended to modify their
+source. Instead, one should use a special auxiliary file to collect
+the signatures of all Fortran routines and insert \fpy specific
+declaration and attribute statements in that file. This auxiliary file
+is called a \emph{signature file} and is identified by the extension
+\texttt{.pyf}.
+
+We can use \fpy to generate these signature files by using the
+\texttt{-h <filename>.pyf} option.
+In our example, \fpy could have been called as follows,
+\shell{f2py -m foo -h foo.pyf exp1.f}
+where the option \texttt{-h foo.pyf} requests \fpy to read the
+routine signatures, save them to the file \texttt{foo.pyf}, and then
+exit.
+If \texttt{exp1.f} in Fig.~\ref{fig:exp1.f} were to
+contain no lines starting with \texttt{Cf2py}, the corresponding
+signature file \texttt{foo.pyf} would be as shown in Fig.~\ref{fig:foo.pyf}.
+In order to obtain the exchanged and more convenient signature
+\texttt{l,u=foo.exp1([n])}, we would edit \texttt{foo.pyf} as shown in
+Fig.~\ref{fig:foom.pyf}.
+The Python C/API extension module \texttt{foo} can be constructed by
+applying \fpy to the signature file with the following command:
+\shell{f2py foo.pyf}
+The procedure for building the corresponding shared module and using
+it in Python is identical to the one described in the previous section.
+
+\begin{figure}[htb]
+ \latexhide{\label{fig:foo.pyf}}
+ \special{html:<BLOCKQUOTE>}
+ \verbatiminput{examples/foo.pyf}
+ \special{html:</BLOCKQUOTE>}
+ \caption{Raw signature file \texttt{foo.pyf} generated with
+ \texttt{f2py -m foo -h foo.pyf exp1.f}}
+ \tthhide{\label{fig:foo.pyf}}
+\end{figure}
+\begin{figure}[htb]
+ \latexhide{\label{fig:foom.pyf}}
+ \special{html:<BLOCKQUOTE>}
+ \verbatiminput{examples/foom.pyf}
+ \special{html:</BLOCKQUOTE>}
+ \caption{Modified signature file \texttt{foo.pyf}}
+ \tthhide{\label{fig:foom.pyf}}
+\end{figure}
+
+As we can see, the syntax of the signature file is an
+extension of the Fortran~90/95 syntax. This means that only a few new
+constructs are introduced for \fpy in addition to all standard Fortran
+constructs; signature files can even be written in fixed form. A
+complete set of constructs that are used when creating interfaces, is
+described in the \fpy User's Guide \cite{f2py-ug}.
+
+
+\section{Basic Features}
+\label{sec:features}
+
+In this section a short overview of \fpy features is given.
+\begin{enumerate}
+\item All basic Fortran types are supported. They include
+the following type specifications:
+\begin{verbatim}
+integer[ | *1 | *2 | *4 | *8 ]
+logical[ | *1 | *2 | *4 | *8 ]
+real[ | *4 | *8 | *16 ]
+complex[ | *8 | *16 | *32 ]
+double precision, double complex
+character[ |*(*)|*1|*2|*3|...]
+\end{verbatim}
+In addition, they can all be in the kind-selector form
+(e.g. \texttt{real(kind=8)}) or char-selector form
+(e.g. \texttt{character(len=5)}).
+\item Arrays of all basic types are supported. Dimension
+ specifications can be of form \texttt{<dimension>} or
+ \texttt{<start>:<end>}. In addition, \texttt{*} and \texttt{:}
+ dimension specifications can be used for input arrays.
+ Dimension specifications may contain also \texttt{PARAMETER}'s.
+\item The following attributes are supported:
+ \begin{itemize}
+ \item
+ \texttt{intent(in)}: used for input-only arguments.
+ \item
+ \texttt{intent(inout)}: used for arguments that are changed in
+ place.
+ \item
+ \texttt{intent(out)}: used for return arguments.
+ \item
+ \texttt{intent(hide)}: used for arguments to be removed from
+ the signature of the Python function.
+ \item
+ \texttt{intent(in,out)}, \texttt{intent(inout,out)}: used for
+ arguments with combined behavior.
+ \item
+ \texttt{dimension(<dimspec>)}
+ \item
+ \texttt{depend([<names>])}: used
+ for arguments that depend on other arguments in \texttt{<names>}.
+ \item
+ \texttt{check([<C booleanexpr>])}: used for checking the
+ correctness of input arguments.
+ \item
+ \texttt{note(<LaTeX text>)}: used for
+ adding notes to the module documentation.
+ \item
+ \texttt{optional}, \texttt{required}
+ \item
+ \texttt{external}: used for call-back arguments.
+ \item
+ \texttt{allocatable}: used for Fortran 90/95 allocatable arrays.
+ \end{itemize}
+\item Using \fpy one can call arbitrary Fortran~77/90/95 subroutines
+ and functions from Python, including Fortran 90/95 module routines.
+\item Using \fpy one can access data in Fortran~77 COMMON blocks and
+ variables in Fortran 90/95 modules, including allocatable arrays.
+\item Using \fpy one can call Python functions from Fortran (call-back
+ functions). \fpy supports very flexible hooks for call-back functions.
+\item Wrapper functions perform the necessary type conversations for their
+ arguments resulting in contiguous Numeric arrays that are suitable for
+ passing to Fortran routines.
+\item \fpy generates documentation strings
+for \texttt{\_\_doc\_\_} attributes of the wrapper functions automatically.
+\item \fpy scans Fortran codes and creates the signature
+ files. It automatically detects the signatures of call-back functions,
+ solves argument dependencies, decides the order of initialization of
+ optional arguments, etc.
+\item \fpy automatically generates GNU Makefiles for compiling Fortran
+ and C codes, and linking them to a shared module.
+ \fpy detects available Fortran and C compilers. The
+ supported compilers include the GNU project C Compiler (gcc), Compaq
+ Fortran, VAST/f90 Fortran, Absoft F77/F90, and MIPSpro 7 Compilers, etc.
+ \fpy has been tested to work on the following platforms: Intel/Alpha
+ Linux, HP-UX, IRIX64.
+\item Finally, the complete \fpy User's Guide is available in various
+ formats (ps, pdf, html, dvi). A mailing list,
+ \email{f2py-users@cens.ioc.ee}, is open for support and feedback. See
+ the FPIG's home page for more information \cite{fpig}.
+\end{enumerate}
+
+
+\section{Implementation Issues}
+\label{sec:impl}
+
+The Fortran to Python interface can be thought of as a three layer
+``sandwich'' of different languages: Python, C, and Fortran. This
+arrangement has two interfaces: Python-C and C-Fortran. Since Python
+itself is written in C, there are no basic difficulties in
+implementing the Python-C interface~\cite{python-doc:ext}. The C-Fortran
+interface, on the other hand, results in many platform and compiler specific
+issues that have to be dealt with. We will now discuss these issues
+in some detail and describe how they are solved in FPIG.
+
+\subsection{Mapping Fortran Types to C Types}
+\label{sec:mapF2Ctypes}
+
+Table \ref{tab:mapf2c} defines how Fortran types are mapped to C types
+in \fpy.
+\begin{table}[htb]
+ \begin{center}
+ \begin{tabular}[c]{l|l}
+ Fortran type & C type \\\hline
+ \texttt{integer *1} & \texttt{char}\\
+ \texttt{byte} & \texttt{char}\\
+ \texttt{integer *2} & \texttt{short}\\
+ \texttt{integer[ | *4]} & \texttt{int}\\
+ \texttt{integer *8} & \texttt{long long}\\
+ \texttt{logical *1} & \texttt{char}\\
+ \texttt{logical *2} & \texttt{short}\\
+ \texttt{logical[ | *4]} & \texttt{int}\\
+ \texttt{logical *8} & \texttt{int}\\
+ \texttt{real[ | *4]} & \texttt{float}\\
+ \texttt{real *8} & \texttt{double}\\
+ \texttt{real *16} & \texttt{long double}\\
+ \texttt{complex[ | *8]} & \texttt{struct \{float r,i;\}}\\
+ \texttt{complex *16} & \texttt{struct \{double r,i;\}}\\
+ \texttt{complex *32} & \texttt{struct \{long double r,i;\}}\\
+ \texttt{character[*...]} & \texttt{char *}\\
+ \end{tabular}
+ \caption{Mapping Fortran types to C types.}
+ \label{tab:mapf2c}
+ \end{center}
+\end{table}
+Users may redefine these mappings by creating a \texttt{.f2py\_f2cmap}
+file in the working directory. This file should contain a Python
+dictionary of dictionaries, e.g. \texttt{\{'real':\{'low':'float'\}\}},
+that informs \fpy to map Fortran type \texttt{real(low)}
+to C type \texttt{float} (here \texttt{PARAMETER low = ...}).
+
+
+\subsection{Calling Fortran (Module) Routines}
+\label{sec:callrout}
+
+When mixing Fortran and C codes, one has to know how function names
+are mapped to low-level symbols in their object files. Different
+compilers may use different conventions for this purpose. For example, gcc
+appends the underscore \texttt{\_} to a Fortran routine name. Other
+compilers may use upper case names, prepend or append different
+symbols to Fortran routine names or both. In any case, if the
+low-level symbols corresponding to Fortran routines are valid for the
+C language specification, compiler specific issues can be solved by
+using CPP macro features.
+
+Unfortunately, there are Fortran compilers that use symbols in
+constructing low-level routine names that are not valid for C. For
+example, the (IRIX64) MIPSpro 7 Compilers use `\$' character in the
+low-level names of module routines which makes it impossible (at
+least directly) to call such routines from C when using the MIPSpro 7
+C Compiler.
+
+In order to overcome this difficulty, FPIG introduces an unique
+solution: instead of using low-level symbols for calling Fortran
+module routines from C, the references to such routines are determined
+at run-time by using special wrappers. These wrappers are called once
+during the initialization of an extension module. They are simple
+Fortran subroutines that use a Fortran module and call another C
+function with Fortran module routines as arguments in order to save
+their references to C global variables that are later used for calling
+the corresponding Fortran module routines. This arrangement is
+set up as follows. Consider the following Fortran 90 module with the
+subroutine \texttt{bar}:
+\special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+module fun
+ subroutine bar()
+ end
+end
+\end{verbatim}
+\special{html:</BLOCKQUOTE>}
+Figure \ref{fig:capi-sketch} illustrates a Python C/API extension
+module for accessing the F90 module subroutine \texttt{bar} from Python.
+When the Python module \texttt{foo} is loaded, \texttt{finitbar} is
+called. \texttt{finitbar} calls \texttt{init\_bar} by passing the
+reference of the Fortran 90 module subroutine \texttt{bar} to C where it is
+saved to the variable \texttt{bar\_ptr}. Now, when one executes \texttt{foo.bar()}
+from Python, \texttt{bar\_ptr} is used in \texttt{bar\_capi} to call
+the F90 module subroutine \texttt{bar}.
+\begin{figure}[htb]
+ \latexhide{\label{fig:capi-sketch}}
+ \special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+#include "Python.h"
+...
+char *bar_ptr;
+void init_bar(char *bar) {
+ bar_ptr = bar;
+}
+static PyObject *
+bar_capi(PyObject *self,PyObject *args) {
+ ...
+ (*((void *)bar_ptr))();
+ ...
+}
+static PyMethodDef
+foo_module_methods[] = {
+ {"bar",bar_capi,METH_VARARGS},
+ {NULL,NULL}
+};
+extern void finitbar_; /* GCC convention */
+void initfoo() {
+ ...
+ finitbar_(init_bar);
+ Py_InitModule("foo",foo_module_methods);
+ ...
+}
+\end{verbatim}
+ \special{html:</BLOCKQUOTE>}
+ \caption{Sketch of Python C/API for accessing F90 module subroutine
+ \texttt{bar}. The Fortran function \texttt{finitbar} is defined in
+ Fig.~\ref{fig:wrapbar}.}
+ \tthhide{\label{fig:capi-sketch}}
+\end{figure}
+\begin{figure}[ht]
+ \latexhide{\label{fig:wrapbar}}
+\special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+ subroutine finitbar(cinit)
+ use fun
+ extern cinit
+ call cinit(bar)
+ end
+\end{verbatim}
+\special{html:</BLOCKQUOTE>}
+ \caption{Wrapper for passing the reference of \texttt{bar} to C code.}
+ \tthhide{\label{fig:wrapbar}}
+\end{figure}
+
+Surprisingly, mixing C code and Fortran modules in this way is as
+portable and compiler independent as mixing C and ordinary Fortran~77
+code.
+
+Note that extension modules generated by \fpy actually use
+\texttt{PyFortranObject} that implements above described scheme with
+exchanged functionalities (see Section \ref{sec:PFO}).
+
+
+\subsection{Wrapping Fortran Functions}
+\label{sec:wrapfunc}
+
+The Fortran language has two types of routines: subroutines and
+functions. When a Fortran function returns a composed type such as
+\texttt{COMPLEX} or \texttt{CHARACTER}-array then calling this
+function directly from C may not work for all compilers, as C
+functions are not supposed to return such references. In order to
+avoid this, FPIG constructs an additional Fortran wrapper subroutine
+for each such Fortran function. These wrappers call just the
+corresponding functions in the Fortran layer and return the result to
+C through its first argument.
+
+
+\subsection{Accessing Fortran Data}
+\label{sec:accsdata}
+
+In Fortran one can use \texttt{COMMON} blocks and Fortran module
+variables to save data that is accessible from other routines. Using
+FPIG, one can also access these data containers from Python. To achieve
+this, FPIG uses special wrapper functions (similar to the ones used
+for wrapping Fortran module routines) to save the references to these
+data containers so that they can later be used from C.
+
+FPIG can also handle \texttt{allocatable} arrays. For example, if a
+Fortran array is not yet allocated, then by assigning it in Python,
+the Fortran to Python interface will allocate and initialize the
+array. For example, the F90 module allocatable array \texttt{bar}
+defined in
+\special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+module fun
+ integer, allocatable :: bar(:)
+end module
+\end{verbatim}
+\special{html:</BLOCKQUOTE>}
+can be allocated from Python as follows
+\special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+>>> import foo
+>>> foo.fun.bar = [1,2,3,4]
+\end{verbatim}
+\special{html:</BLOCKQUOTE>}
+
+\subsection{\texttt{PyFortranObject}}
+\label{sec:PFO}
+
+In general, we would like to access from Python the following Fortran
+objects:
+\begin{itemize}
+\item subroutines and functions,
+\item F90 module subroutines and functions,
+\item items in COMMON blocks,
+\item F90 module data.
+\end{itemize}
+Assuming that the Fortran source is available, we can determine the signatures
+of these objects (the full specification of routine arguments, the
+layout of Fortran data, etc.). In fact, \fpy gets this information
+while scanning the Fortran source.
+
+In order to access these Fortran objects from C, we need to determine
+their references. Note that the direct access of F90 module objects is
+extremely compiler dependent and in some cases even impossible.
+Therefore, FPIG uses various wrapper functions for obtaining the
+references to Fortran objects. These wrapper functions are ordinary
+F77 subroutines that can easily access objects from F90 modules and
+that pass the references to Fortran objects as C variables.
+
+
+\fpy generated Python C/API extension modules use
+\texttt{PyFortranObject} to store the references of Fortran objects.
+In addition to the storing functionality, the \texttt{PyFortranObject}
+also provides methods for accessing/calling Fortran objects from
+Python in a user-friendly manner. For example, the item \texttt{a} in
+\texttt{COMMON /bar/ a(2)} can be accessed from Python as
+\texttt{foo.bar.a}.
+
+Detailed examples of \texttt{PyFortranObject} usage can be found in
+\cite{PFO}.
+
+\subsection{Callback Functions}
+\label{sec:callback}
+
+Fortran routines may have arguments specified as \texttt{external}.
+These arguments are functions or subroutines names that the receiving Fortran routine
+will call from its body. For such arguments FPIG
+constructs a call-back mechanism (originally contributed by Travis
+Oliphant) that allows Fortran routines to call Python functions. This
+is actually realized using a C layer between Python and
+Fortran. Currently, the call-back mechanism is compiler independent
+unless a call-back function needs to return a composed type
+(e.g. \texttt{COMPLEX}).
+
+The signatures of call-back functions are determined when \fpy scans
+the Fortran source code. To illustrate this, consider the following
+example:
+\special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+ subroutine foo(bar, fun, boo)
+ integer i
+ real r
+ external bar,fun,boo
+ call bar(i, 1.2)
+ r = fun()
+ call sun(boo)
+ end
+\end{verbatim}
+\special{html:</BLOCKQUOTE>}
+\fpy recognizes the signatures of the user routines \texttt{bar} and
+\texttt{fun} using the information contained in the lines \texttt{call
+ bar(i, 1.2)} and \texttt{r = fun()}:
+\special{html:<BLOCKQUOTE>}
+\begin{verbatim}
+subroutine bar(a,b)
+ integer a
+ real b
+end
+function fun()
+ real fun
+end
+\end{verbatim}
+\special{html:</BLOCKQUOTE>}
+But \fpy cannot determine the signature of the user routine
+\texttt{boo} because the source contains no information at all about
+the \texttt{boo} specification. Here user needs to provide the
+signature of \texttt{boo} manually.
+
+\section{Future Work}
+\label{sec:future}
+
+FPIG can be used to wrap almost any Fortran code. However, there are
+still issues that need to be resolved. Some of them are listed below:
+\begin{enumerate}
+\item One of the FPIG's goals is to become as platform and compiler
+ independent as possible. Currently FPIG can be used on
+ any UN*X platform that has gcc installed in it. In the future, FPIG
+ should be also tested on Windows systems.
+\item Another goal of FPIG is to become as simple to use as
+ possible. To achieve that, FPIG should start using the facilities of
+ \texttt{distutils}, the new Python standard to distribute and build
+ Python modules. Therefore, a contribution to \texttt{distutils}
+ that can handle Fortran extensions should be developed.
+\item Currently users must be aware of
+ the fact that multi-dimensional arrays are stored differently in C
+ and Fortran (they must provide transposed multi-dimensional arrays
+ to wrapper functions). In the future a solution should be found such
+ that users do not need to worry about this rather
+ confusing and technical detail.
+\item Finally, a repository of signature files for widely-used Fortran
+ libraries (e.g. BLAS, LAPACK, MINPACK, ODEPACK, EISPACK, LINPACK) should be
+ provided.
+\end{enumerate}
+
+
+\section{Application to a Large Aero-Structural Analysis Framework}
+\label{sec:app}
+
+
+\subsection{The Need for Python and FPIG}
+\label{sec:appsub1}
+
+As a demonstration of the power and usefulness of FPIG, we will
+present work that has been done at the Aerospace Computing Laboratory
+at Stanford University. The focus of the research is on aircraft
+design optimization using high-fidelity analysis tools such as
+Computational Fluid Dynamics (CFD) and Computational Structural
+Mechanics (CSM)~\cite{reno99}.
+
+The group's analysis programs are written mainly in Fortran and are the result
+of many years of development. Until now, any researcher that needed
+to use these tools would have to learn a less than user-friendly
+interface and become relatively familiar with the inner workings of
+the codes before starting the research itself. The need to
+couple analyses of different disciplines revealed the additional
+inconvenience of gluing and scripting the different codes with
+Fortran.
+
+It was therefore decided that the existing tools should be wrapped
+using an object-oriented language in order to improve their ease of
+use and versatility. The use of several different languages such as
+C++, Java and Perl was investigated but Python seemed to provide the
+best solution. The fact that it combines scripting capability
+with a fully-featured object-oriented programming language, and that
+it has a clean syntax were factors that determined our choice. The
+introduction of tools that greatly facilitate the task of wrapping
+Fortran with Python provided the final piece needed to realize our
+objective.
+
+\subsection{Wrapping the Fortran Programs}
+
+In theory, it would have been possible to wrap our Fortran programs
+with C and then with Python by hand. However, this would have been a
+labor intensive task that would detract from our research. The use of
+tools that automate the task of wrapping has been extremely useful.
+
+The first such tool that we used was PyFort. This tool created the C
+wrappers and Python modules automatically, based on signature files
+(\texttt{.pyf}) provided by the user. Although it made the task of
+wrapping considerably easier, PyFort was limited by the fact that any
+Fortran data that was needed at the Python level had to be passed in
+the argument list of the Fortran subroutine. Since the bulk of the
+data in our programs is shared by using Fortran~77 common blocks and
+Fortran~90 modules, this required adding many more arguments to the
+subroutine headers. Furthermore, since Fortran does not allow common
+block variables or module data to be specified in a subroutine
+argument list, a dummy pointer for each desired variable had to be
+created and initialized.
+
+The search for a better solution to this problem led us to \fpy.
+Since \fpy provides a solution for accessing common block and module
+variables, there was no need to change the Fortran source anymore,
+making the wrapping process even easier. With \fpy we also
+experienced an increased level of automation since it produces the
+signature files automatically, as well as a Makefile for the joint
+compilation of the original Fortran and C wrapper codes. This increased
+automation did not detract from its flexibility since it was always
+possible to edit the signature files to provide different functionality.
+
+Once Python interfaces were created for each Fortran application
+by running \fpy, it was just a matter of using Python to achieve the
+final objective of developing an object-oriented framework for our
+multidisciplinary solvers. The Python modules that we designed are
+discussed in the following section.
+
+
+\subsection{Module Design}
+\label{ssec:module}
+
+The first objective of this effort was to design the classes for each
+type of analysis, each representing an independent Python module. In
+our case, we are interested in performing aero-structural analysis and
+optimization of aircraft wings. We therefore needed an analysis tool
+for the flow (CFD), another for analyzing the structure (CSM), as well
+as a geometry database. In addition, we needed to interface these two
+tools in order to analyze the coupled system. The object design for
+each of these modules should be general enough that the underlying
+analysis code in Fortran can be changed without changing the Python
+interface. Another requirement was that the modules be usable on
+their own for single discipline analysis.
+
+\subsubsection{Geometry}
+
+The \emph{Geometry} class provides a database for the outer mold
+geometry of the aircraft. This database needs to be accessed by both
+the flow and structural solvers. It contains a parametric description
+of the aircraft's surface as well as methods that extract and update
+this information.
+
+
+\subsubsection{Flow}
+
+The flow solver was wrapped in a class called \emph{Flow}. The class
+was designed so that it can wrap any type of CFD solver. It contains
+two main objects: the computational mesh and a solver object. A graph
+showing the hierarchy of the objects in \emph{Flow} is shown in
+Fig.~\ref{fig:flow}.
+\tthhide{
+\begin{figure}[h]
+ \centering
+ \epsfig{file=./flow.eps, angle=0, width=.7\linewidth}
+ \caption{The \emph{Flow} container class.}
+ \label{fig:flow}
+\end{figure}
+}
+\latexhide{
+\begin{figure}[h]
+ \label{fig:flow}
+\special{html:
+<CENTER>
+ <IMG SRC="flow.jpg" WIDTH="400">
+</CENTER>
+}
+ \caption{The \emph{Flow} container class.}
+\end{figure}
+}
+Methods in the flow class include those used for the initialization of
+all the class components as well as methods that write the current
+solution to a file.
+
+
+\subsubsection{Structure}
+
+The \emph{Structure} class wraps a structural analysis code. The class
+stores the information about the structure itself in an object called
+\emph{Model} which also provides methods for changing and exporting
+its information. A list of the objects contained in this class can be
+seen in Fig.~\ref{fig:structure}.
+\tthhide{
+\begin{figure}[h]
+ \centering
+ \epsfig{file=./structure.eps, angle=0, width=.7\linewidth}
+ \caption{The \emph{Structure} container class.}
+ \label{fig:structure}
+\end{figure}
+}
+\latexhide{
+\begin{figure}[h]
+ \label{fig:structure}
+\special{html:
+<CENTER>
+ <IMG SRC="structure.jpg" WIDTH="400">
+</CENTER>
+}
+ \caption{The \emph{Structure} container class.}
+\end{figure}
+}
+Since the \emph{Structure} class contains a
+dictionary of \emph{LoadCase} objects, it is able to store and solve
+multiple load cases, a capability that the original Fortran code
+does not have.
+
+
+\subsubsection{Aerostructure}
+
+The \emph{Aerostructure} class is the main class in the
+aero-structural analysis module and contains a \emph{Geometry}, a
+\emph{Flow} and a \emph{Structure}. In addition, the class defines
+all the functions that are necessary to translate aerodynamic
+loads to structural loads and structural displacements to
+geometry surface deformations.
+
+One of the main methods of this class is the one that solves the
+aeroelastic system. This method is printed below:
+\begin{verbatim}
+def Iterate(self, load_case):
+ """Iterates the aero-structural solution."""
+ self.flow.Iterate()
+ self._UpdateStructuralLoads()
+ self.structure.CalcDisplacements(load_case)
+ self.structure.CalcStresses(load_case)
+ self._UpdateFlowMesh()
+ return
+\end{verbatim}
+This is indeed a very readable script, thanks to Python, and any
+high-level changes to the solution procedure can be easily
+implemented.
+The \emph{Aerostructure} class also contains methods that export all
+the information on the current solution for visualization, an example
+of which is shown in the next section.
+
+
+\subsection{Results}
+
+In order to visualize results, and because we needed to view results
+from multiple disciplines simultaneously, we selected OpenDX. Output
+files in DX format are written at the Python level and the result can
+be seen in Fig.~\ref{fig:aerostructure} for the case of a transonic
+airliner configuration.
+\tthhide{
+\begin{figure*}[t]
+ \centering
+ \epsfig{file=./aerostructure.eps, angle=-90, width=\linewidth}
+ \caption{Aero-structural model and results.}
+ \label{fig:aerostructure}
+\end{figure*}
+}
+\latexhide{
+\begin{figure}[h]
+ \label{fig:aerostructure}
+\special{html:
+<CENTER>
+ <IMG SRC="aerostructure.jpg" WIDTH="600">
+</CENTER>
+}
+ \caption{Aero-structural model and results.}
+\end{figure}
+}
+
+
+The figure illustrates the multidisciplinary nature of the
+problem. The grid pictured in the background is the mesh used by the
+flow solver and is colored by the pressure values computed at the
+cell centers. The wing in the foreground and its outer surface is
+clipped to show the internal structural components which are colored
+by their stress value.
+
+In conclusion, \fpy and Python have been extremely useful tools in our
+pursuit for increasing the usability and flexibility of existing Fortran
+tools.
+
+
+\begin{thebibliography}{99}
+\bibitem{netlib}
+\newblock Netlib repository at UTK and ORNL.
+\newblock \\\wwwsite{http://www.netlib.org/}
+\bibitem{python}
+Python language.
+\newblock \\\wwwsite{http://www.python.org/}
+\bibitem{swig}
+SWIG --- Simplified Wrapper and Interface Generator.
+\newblock \\\wwwsite{http://www.swig.org/}
+\bibitem{pyfort}
+PyFort --- The Python-Fortran connection tool.
+\newblock \\\wwwsite{http://pyfortran.sourceforge.net/}
+\bibitem{fpig}
+FPIG --- Fortran to Python Interface Generator.
+\newblock \\\wwwsite{http://cens.ioc.ee/projects/f2py2e/}
+\bibitem{numpy}
+Numerical Extension to Python.
+\newblock \\\wwwsite{http://numpy.sourceforge.net/}
+\bibitem{graham-etal}
+R. L. Graham, D. E. Knuth, and O. Patashnik.
+\newblock {\em {C}oncrete {M}athematics: a foundation for computer science.}
+\newblock Addison-Wesley, 1988
+\bibitem{f2py-ug}
+P. Peterson.
+\newblock {\em {\tt f2py} - Fortran to Python Interface Generator. Second Edition.}
+\newblock 2000
+\newblock
+\\\wwwsite{http://cens.ioc.ee/projects/f2py2e/usersguide.html}
+\bibitem{python-doc:ext}
+Python Documentation: Extending and Embedding.
+\newblock \\\wwwsite{http://www.python.org/doc/ext/}
+\bibitem{PFO}
+P. Peterson. {\em {\tt PyFortranObject} example usages.}
+\newblock 2001
+\newblock \\\wwwsite{http://cens.ioc.ee/projects/f2py2e/pyfobj.html}
+\bibitem{reno99}
+Reuther, J., J. J. Alonso, J. R. R. A. Martins, and
+S. C. Smith.
+\newblock ``A Coupled Aero-Structural Optimization Method for
+ Complete Aircraft Configurations'',
+\newblock {\em Proceedings of the 37th Aerospace Sciences Meeting},
+\newblock AIAA Paper 1999-0187. Reno, NV, January, 1999
+\end{thebibliography}
+
+%\end{multicols}
+
+%\begin{figure}[htbp]
+% \begin{center}
+% \epsfig{file=aerostructure2b.ps,width=0.75\textwidth}
+% \end{center}
+%\end{figure}
+
+
+
+\end{document}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
+
+
diff --git a/numpy/f2py/doc/signaturefile.tex b/numpy/f2py/doc/signaturefile.tex new file mode 100644 index 000000000..3cd16d890 --- /dev/null +++ b/numpy/f2py/doc/signaturefile.tex @@ -0,0 +1,368 @@ + +\section{Signature file} +\label{sec:signaturefile} + +The syntax of a signature file is borrowed from the Fortran~90/95 +language specification. Almost all Fortran~90/95 standard constructs +are understood. Recall that Fortran~77 is a subset of Fortran~90/95. +This tool introduces also some new attributes that are used for +controlling the process of Fortran to Python interface construction. +In the following, a short overview of the constructs +used in signature files will be given. + + +\subsection{Module block} +\label{sec:moduleblock} + +A signature file contains one or more \texttt{pythonmodule} blocks. A +\texttt{pythonmodule} block has the following structure: +\begin{verbatim} +python module <modulename> + interface + <routine signatures> + end [interface] + interface + module <F90/95 modulename> + <F90 module data type declarations> + <F90 module routine signatures> + end [module [<F90/95 modulename>]] + end [interface] +end [pythonmodule [<modulename>]] +\end{verbatim} +For each \texttt{pythonmodule} block \fpy will generate a C-file +\texttt{<modulename>module.c} (see step (iii)). (This is not true if +\texttt{<modulename>} contains substring \texttt{\_\_user\_\_}, see +Sec.~\ref{sec:cbmodule} and \texttt{external} attribute). + +\subsection{Signatures of Fortran routines and Python functions} +\label{sec:routineblock} + + +The signature of a Fortran routine has the following structure: +\begin{verbatim} +[<typespec>] function|subroutine <routine name> [([<arguments>])] \ + [result (<entityname>)] + [<argument type declarations>] + [<argument attribute statements>] + [<use statements>] + [<common block statements>] + [<other statements>] +end [function|subroutine [<routine name>]] +\end{verbatim} + +Let us introduce also the signature of the corresponding wrapper +function: +\begin{verbatim} +def <routine name>(<required arguments>[,<optional arguments>]): + ... + return <return variables> +\end{verbatim} + +Before you edit the signature file, you should first decide what is the +desired signature of the corresponding Python function. \fpy offers +many possibilities to control the interface construction process: you +may want to insert/change/remove various attributes in the +declarations of the arguments in order to change the appearance +of the arguments in the Python wrapper function. + +\begin{itemize} +\item +The definition of the \texttt{<argument type declaration>} is +\begin{verbatim} +<typespec> [[<attrspec>]::] <entitydecl> +\end{verbatim} +where +\begin{verbatim} +<typespec> := byte | character[<charselector>] + | complex[<kindselector>] | real[<kindselector>] + | double complex | double precision + | integer[<kindselector>] | logical[<kindselector>] +\end{verbatim} +\begin{verbatim} +<charselector> := *<charlen> | ([len=]<len>[,[kind]<kind>]) + | (kind=<kind>[,len=<len>]) +<kindselector> := *<intlen> | ([kind=]<kind>) +\end{verbatim} +(there is no sense to modify \texttt{<typespec>}s generated by \fpy). +\texttt{<attrspec>} is a comma separated list of attributes (see +Sec.~\ref{sec:attributes}); +\begin{verbatim} +<entitydecl> := <name> [[*<charlen>][(<arrayspec>)] + | [(<arrayspec>)]*<charlen>] + | [/<init_expr>/ | =<init_expr>] [,<entitydecl>] +\end{verbatim} +where \texttt{<arrayspec>} is a comma separated list of dimension +bounds; \texttt{<init\_expr>} is a C-expression (see +Sec.~\ref{sec:C-expr}). If an argument is not defined with +\texttt{<argument type declaration>}, its type is determined by +applying \texttt{implicit} rules (if it is not specifyied, then +standard rules are applied). + +\item The definition of the \texttt{<argument attribute statement>} is +a short form of the \texttt{<argument type declaration>}: +\begin{verbatim} +<attrspec> <entitydecl> +\end{verbatim} + +\item \texttt{<use statement>} is defined as follows +\begin{verbatim} +use <modulename> [,<rename_list> | ,ONLY:<only_list>] +<rename_list> := local_name=>use_name [,<rename_list>] +\end{verbatim} + Currently the \texttt{use} statement is used to link call-back + modules (Sec.~\ref{sec:cbmodule}) and the \texttt{external} + arguments (call-back functions). + +\item \texttt{<common block statement>} is defined as follows +\begin{verbatim} +common /<commonname>/ <shortentitydecl> +\end{verbatim} +where +\begin{verbatim} +<shortentitydecl> := <name> [(<arrayspec>)] [,<shortentitydecl>] +\end{verbatim} +One \texttt{module} block should not contain two or more +\texttt{common} blocks with the same name. Otherwise, the later ones +are ignored. The types of variables in \texttt{<shortentitydecl>} can +be defined in \texttt{<argument type declarations>}. Note that there +you can specify also the array specifications; then you don't need to +do that in \texttt{<shortentitydecl>}. +\end{itemize} + +\subsection{Attributes} +\label{sec:attributes} + +The following attributes are used by \fpy: +\begin{description} +\item[\texttt{optional}] --- the variable is moved to the end of + optional argument list of the wrapper function. Default value of an + optional argument can be specified using \texttt{<init\_expr>} in + \texttt{entitydecl}. You can use \texttt{optional} attribute also for + \texttt{external} arguments (call-back functions), but it is your + responsibility to ensure that it is given by the user if Fortran + routine wants to call it. +\item[\texttt{required}] --- the variable is considered as a required + argument (that is default). You will need this in order to overwrite + the \texttt{optional} attribute that is automatically set when + \texttt{<init\_expr>} is used. However, usage of this attribute + should be rare. +\item[\texttt{dimension(<arrayspec>)}] --- used when the variable is + an array. For unbounded dimensions symbols `\texttt{*}' or + `\texttt{:}' can be used (then internally the corresponding + dimensions are set to -1; you'll notice this when certain exceptions + are raised). +\item[\texttt{external}] --- the variable is a call-back function. \fpy will + construct a call-back mechanism for this function. Also call-back + functions must be defined by their signatures, and there are several + ways to do that. In most cases, \fpy will be able to determine the signatures + of call-back functions from the Fortran source code; then it + builds an additional \texttt{module} block with a name containing + string `\texttt{\_\_user\_\_}' (see Sec.~\ref{sec:cbmodule}) and + includes \texttt{use} statement to the routines signature. Anyway, + you should check that the generated signature is correct. + + Alternatively, you can specify the signature by inserting to the + routines block a ``model'' how the call-back function would be called + from Fortran. For subroutines you should use\\ + \hspace*{2em}\texttt{call <call-back name>(<arguments>)}\\ + and for functions\\% + \hspace*{2em}\texttt{<return value> = <call-back name>(<arguments>)}\\ + The variables in \texttt{<arguments>} and \texttt{<return value>} + must be defined as well. You can use the arguments of the main + routine, for instance. +\item[\texttt{intent(<intentspec>)}] --- this specifies the + ``intention'' of the variable. \texttt{<intentspec>} is a comma + separated list of the following specifications: + \begin{description} + \item[\texttt{in}] --- the variable is considered to be an input + variable (default). It means that the Fortran function uses only + the value(s) of the variable and is assumed not to change it. + \item[\texttt{inout}] --- the variable is considered to be an + input/output variable which means that Fortran routine may change + the value(s) of the variable. Note that in Python only array + objects can be changed ``in place''. (\texttt{intent(outin)} is + \texttt{intent(inout)}.) + \item[\texttt{out}] --- the value of the (output) variable is + returned by the wrapper function: it is appended to the list of + \texttt{<returned variables>}. If \texttt{out} is specified alone, + also \texttt{hide} is assumed. + \item[\texttt{hide}] --- use this if the variable \emph{should not} + or \emph{need not} to be in the list of wrapper function arguments + (not even in optional ones). For example, this is assumed if + \texttt{intent(out)} is used. You can ``hide'' an argument if it + has always a constant value specified in \texttt{<init\_expr>}, + for instance. + \end{description} + The following rules apply: + \begin{itemize} + \item if no \texttt{intent} attribute is specified, \texttt{intent(in)} is + assumed; + \item \texttt{intent(in,inout)} is \texttt{intent(in)}; + \item \texttt{intent(in,hide)}, \texttt{intent(inout,hide)} are \texttt{intent(hide)}; + \item \texttt{intent(out)} is \texttt{intent(out,hide)}; +\item \texttt{intent(inout)} is NOT \texttt{intent(in,out)}. + \end{itemize} + In conclusion, the following combinations are ``minimal'': + \texttt{intent(in)}, \texttt{intent(inout)}, \texttt{intent(out)}, + \texttt{intent(hide)}, \texttt{intent(in,out)}, and + \texttt{intent(inout,out)}. +\item[\texttt{check([<C-booleanexpr>])}] --- if + \texttt{<C-booleanexpr>} evaluates to zero, an exception is raised + about incorrect value or size or any other incorrectness of the + variable. If \texttt{check()} or \texttt{check} is used then \fpy + will not try to guess the checks automatically. +\item[\texttt{depend([<names>])}] --- the variable depends on other + variables listed in \texttt{<names>}. These dependence relations + determine the order of internal initialization of the variables. If + you need to change these relations then be careful not to break the + dependence relations of other relevant variables. If + \texttt{depend()} or \texttt{depend} is used then \fpy will not try + to guess the dependence relations automatically. +\item[\texttt{note(<LaTeX text>)}] --- with this attribute you can + include human readable documentation strings to the LaTeX document + that \fpy generates. Do not insert here information that \fpy can + establish by itself, such as, types, sizes, lengths of the + variables. Here you can insert almost arbitrary LaTeX text. Note + that \texttt{<LaTeX text>} is mainly used inside the LaTeX + \texttt{description} environment. Hint: you can use + \texttt{\bs{}texttt\{<name>\}} for typesetting variable \texttt{<name>} + in LaTeX. In order to get a new line to the LaTeX document, use + \texttt{\bs{}n} followed by a space. For longer text, you may want + to use line continuation feature of Fortran 90/95 language: set + \texttt{\&} (ampersand) + to be the last character in a line. +\item[\texttt{parameter}] --- the variable is parameter and it must + have a value. If the parameter is used in dimension specification, + it is replaced by its value. (Are there any other usages of + parameters except in dimension specifications? Let me know and I'll + add support for it). +\end{description} + + +\subsection{C-expressions} +\label{sec:C-expr} + +The signature of a routine may contain C-expressions in +\begin{itemize} +\item \texttt{<init\_expr>} for initializing particular variable, or in +\item \texttt{<C-booleanexpr>} of the \texttt{check} attribute, or in +\item \texttt{<arrayspec>} of the \texttt{dimension} attribute. +\end{itemize} +A C-expression may contain +\begin{itemize} +\item standard C-statement, +\item functions offered in \texttt{math.h}, +\item previously initialized variables (study +the dependence relations) from the argument list, and +\item the following CPP-macros: + \begin{description} + \item[\texttt{len(<name>)}] --- the length of an array \texttt{<name>}; + \item[\texttt{shape(<name>,<n>)}] --- the $n$-th dimension of an array + \texttt{<name>}; + \item[\texttt{rank(<name>)}] --- the rank of an array \texttt{<name>}; + \item[\texttt{slen(<name>)}] --- the length of a string \texttt{<name>}. + \end{description} +\end{itemize} + + +In addition, when initializing arrays, an index vector \texttt{int + \_i[rank(<name>)];} +is available: \texttt{\_i[0]} refers to +the index of the first dimension, \texttt{\_i[1]} to the index of +the second dimension, etc. For example, the argument type declaration\\ +\hspace*{2em}\texttt{integer a(10) = \_i[0]}\\ +is equivalent with the following Python statement\\ +\hspace*{2em}\texttt{a = array(range(10))} + + +\subsection{Required/optional arguments} +\label{sec:reqoptargs} + +When \texttt{optional} attribute is used (including the usage of +\texttt{<init\_expr>} without the \texttt{required} attribute), the +corresponding variable in the argument list of a Fortran routine is +appended to the optional argument list of the wrapper function. + +For optional array argument all dimensions must be bounded (not +\texttt{(*)} or \texttt{(:)}) and defined at the time of +initialization (dependence relations). + +If the \texttt{None} object is passed in in place of a required array +argument, it will be considered as optional: that is, the memory is +allocated (of course, if it has unbounded dimensions, an exception +will be raised), and if \texttt{<init\_expr>} is defined, +initialization is carried out. + + +\subsection{Internal checks} +\label{sec:intchecks} + +All array arguments are checked against the correctness of their rank. +If there is a mismatch, \fpy attempts to fix that by constructing an +array with a correct rank from the given array argument (there will be +no performance hit as no data is copied). The freedom to do so is +given only if some dimensions are unbounded or their value is 1. An +exception is raised when the sizes will not match. + +All bounded dimensions of an array are checked to be larger or equal +to the dimensions specified in the signature. + +So, you don't need to give explicit \texttt{check} attributes to check +these internal checks. + + +\subsection{Call-back modules} +\label{sec:cbmodule} + +A Fortran routine may have \texttt{external} arguments (call-back +functions). The signatures of the call-back functions must be defined +in a call-back \texttt{module} block (its name contains +\texttt{\_\_user\_\_}), in general; other possibilities are described +in the \texttt{external} attribute specification (see +Sec.~\ref{sec:attributes}). For the signatures of call-back +functions the following restrictions apply: +\begin{itemize} +\item Attributes \texttt{external}, \texttt{check(...)}, and + initialization statements are ignored. +\item Attribute \texttt{optional} is used only for changing the order + of the arguments. +\item For arrays all dimension bounds must be specified. They may be + C-expressions containing variables from the argument list. + Note that here CPP-macros \texttt{len}, \texttt{shape}, + \texttt{rank}, and \texttt{slen} are not available. +\end{itemize} + + +\subsection{Common blocks} +\label{sec:commonblocks} + +All fields in a common block are mapped to arrays of appropriate sizes +and types. Scalars are mapped to rank-0 arrays. For multi-dimensional +fields the corresponding arrays are transposed. In the type +declarations of the variables representing the common block fields, +only \texttt{dimension(<arrayspec>)}, \texttt{intent(hide)}, and +\texttt{note(<LaTeX text>)} attributes are used, others are ignored. + +\subsection{Including files} +\label{sec:include} + +You can include files to the signature file using +\begin{verbatim} +include '<filename>' +\end{verbatim} +statement. It can be used in any part of the signature file. +If the file \texttt{<filename>} does not exists or it is not in the path, +the \texttt{include} line is ignored. + +\subsection{\fpy directives} +\label{sec:directives} + +You can insert signature statements directly to Fortran source codes +as comments. Anything that follows \texttt{<comment char>f2py} is +regarded as normal statement for \fpy. + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "f2py2e" +%%% End: + diff --git a/numpy/f2py/doc/using_F_compiler.txt b/numpy/f2py/doc/using_F_compiler.txt new file mode 100644 index 000000000..3067f0776 --- /dev/null +++ b/numpy/f2py/doc/using_F_compiler.txt @@ -0,0 +1,147 @@ + +Title: Wrapping F compiled Fortran 90 modules with F2PY + ================================================ + +Rationale: The F compiler does not support external procedures which + makes it impossible to use it in F2PY in a normal way. + This document describes a workaround to this problem so + that F compiled codes can be still wrapped with F2PY. + +Author: Pearu Peterson +Date: May 8, 2002 + +Acknowledgement: Thanks to Siegfried Gonzi who hammered me to produce + this document. + +Normally wrapping Fortran 90 modules to Python using F2PY is carried +out with the following command + + f2py -c -m fun foo.f90 + +where file foo.f90 contains, for example, + +module foo + public :: bar + contains + subroutine bar (a) + integer,intent(inout) :: a + print *,"Hello from foo.bar" + print *,"a=",a + a = a + 5 + print *,"a=",a + end subroutine bar +end module foo + +Then with a supported F90 compiler (running `f2py -c --help-compiler' +will display the found compilers) f2py will generate an extension +module fun.so into the current directory and the Fortran module foo +subroutine bar can be called from Python as follows + +>>> import fun +>>> print fun.foo.bar.__doc__ +bar - Function signature: + bar(a) +Required arguments: + a : in/output rank-0 array(int,'i') + +>>> from Numeric import array +>>> a = array(3) +>>> fun.foo.bar(a) + Hello from foo.bar + a= 3 + a= 8 +>>> a +8 +>>> + +This works nicely with all supported Fortran compilers. + +However, the F compiler (http://www.fortran.com/F/compilers.html) is +an exception. Namely, the F compiler is designed to recognize only +module procedures (and main programs, of course) but F2PY needs to +compile also the so-called external procedures that it generates to +facilitate accessing Fortran F90 module procedures from C and +subsequently from Python. As a result, wrapping F compiled Fortran +procedures to Python is _not_ possible using the simple procedure as +described above. But, there is a workaround that I'll describe below +in five steps. + +1) Compile foo.f90: + + F -c foo.f90 + +This creates an object file foo.o into the current directory. + +2) Create the signature file: + + f2py foo.f90 -h foo.pyf + +This creates a file foo.pyf containing + +module foo ! in foo.f90 + real public :: bar + subroutine bar(a) ! in foo.f90:foo + integer intent(inout) :: a + end subroutine bar +end module foo + +3) Open the file foo.pyf with your favorite text editor and change the + above signature to + +python module foo + interface + subroutine bar(a) + fortranname foo_MP_bar + intent(c) bar + integer intent(in,out) :: a + end subroutine bar + end interface +end python module foo + +The most important modifications are + + a) adding `python' keyword everywhere before the `module' keyword + + b) including an `interface' block around the all subroutine blocks. + + c) specifying the real symbol name of the subroutine using + `fortranname' statement. F generated symbol names are in the form + <module name>_MP_<subroutine name> + + d) specifying that subroutine is `intent(c)'. + +Notice that the `intent(inout)' attribute is changed to +`intent(in,out)' that instructs the wrapper to return the modified +value of `a'. + +4) Build the extension module + + f2py -c foo.pyf foo.o --fcompiler=Gnu /opt/F/lib/quickfit.o \ + /opt/F/lib/libf96.a + +This will create the extension module foo.so into the current +directory. Notice that you must use Gnu compiler (gcc) for linking. +And the paths to F specific object files and libraries may differ for +your F installation. + +5) Finally, we can call the module subroutine `bar' from Python + +>>> import foo +>>> print foo.bar.__doc__ +bar - Function signature: + a = bar(a) +Required arguments: + a : input int +Return objects: + a : int + +>>> foo.bar(3) +8 +>>> + +Notice that the F compiled module procedures are called as ordinary +external procedures. Also I/O seems to be lacking for F compiled +Fortran modules. + +Enjoy, + Pearu diff --git a/numpy/f2py/doc/win32_notes.txt b/numpy/f2py/doc/win32_notes.txt new file mode 100644 index 000000000..1b7b9029c --- /dev/null +++ b/numpy/f2py/doc/win32_notes.txt @@ -0,0 +1,85 @@ +The following notes are from Eric Jones.
+
+My Setup:
+
+For Python/Fortran development, I run Windows 2000 and use the mingw32
+(www.mingw.org) set of gcc/g77 compilers and tools (gcc 2.95.2) to build python
+extensions. I'll also ocassionally use MSVC for extension development, but
+rarely on projects that include Fortran code. This short HOWTO describes how
+I use f2py in the Windows environment. Pretty much everything is done from
+a CMD (DOS) prompt, so you'll need to be familiar with using shell commands.
+
+Installing f2py:
+
+Before installing f2py, you'll need to install python. I use python2.1 (maybe
+python2.2 will be out by the time you read this). Any version of Python beyond
+version 1.52 should be fine. See www.python.org for info on installing Python.
+
+You'll also need Numeric which is available at
+http://sourceforge.net/projects/numpy/. The latest version is 20.3.
+
+Since Pearu has moved to a setup.py script, installation is pretty easy. You
+can download f2py from http://cens.ioc.ee/projects/f2py2e/. The latest public
+release is http://cens.ioc.ee/projects/f2py2e/rel-3.x/f2py-3.latest.tgz. Even
+though this is a .tgz file instead of a .zip file, most standard compression
+utilities such as WinZip (www.winzip.com) handle unpacking .tgz files
+automatically. Here are the download steps:
+
+ 1. Download the latest version of f2py and save it to disk.
+
+ 2. Use WinZip or some other tool to open the "f2py.xxx.tgz" file.
+ a. When WinZip says archive contains one file, "f2py.xxx.tar"
+ and ask if it should open it, respond with "yes".
+ b. Extract (use the extract button at the top) all the files
+ in the archive into a file. I'll use c:\f2py2e
+
+ 3. Open a cmd prompt by clicking start->run and typing "cmd.exe".
+ Now type the following commands.
+
+ C:\WINDOWS\SYSTEM32> cd c:\f2py2e
+ C:\F2PY2E> python setup.py install
+
+ This will install f2py in the c:\python21\f2py2e directory. It
+ also copies a few scripts into the c:\python21\Scripts directory.
+ Thats all there is to installing f2py. Now lets set up the environment
+ so that f2py is easy to use.
+
+ 4. You need to set up a couple of environement variables. The path
+ "c:\python21\Scripts" needs to be added to your path variables.
+ To do this, go to the enviroment variables settings page. This is
+ where it is on windows 2000:
+
+ Desktop->(right click)My Computer->Properties->Advanced->
+ Environment Variables
+
+ a. Add "c:\python21\Scripts" to the end of the Path variable.
+ b. If it isn't already there, add ".py" to the PATHEXT variable.
+ This tells the OS to execute f2py.py even when just "f2py" is
+ typed at a command prompt.
+
+ 5. Well, there actually isn't anything to be done here. The Python
+ installation should have taken care of associating .py files with
+ Python for execution, so you shouldn't have to do anything to
+ registry settings.
+
+To test your installation, open a new cmd prompt, and type the following:
+
+ C:\WINDOWS\SYSTEM32> f2py
+ Usage:
+ f2py [<options>] <fortran files> [[[only:]||[skip:]] \
+ <fortran functions> ] \
+ [: <fortran files> ...]
+ ...
+
+This prints out the usage information for f2py. If it doesn't, there is
+something wrong with the installation.
+
+Testing:
+The f2py test scripts are kinda Unix-centric, so they don't work under windows.
+
+XXX include test script XXX.
+
+Compiler and setup.py issues:
+
+XXX
+
diff --git a/numpy/f2py/docs/FAQ.txt b/numpy/f2py/docs/FAQ.txt new file mode 100644 index 000000000..e2ed79445 --- /dev/null +++ b/numpy/f2py/docs/FAQ.txt @@ -0,0 +1,615 @@ + +====================================================================== + F2PY Frequently Asked Questions +====================================================================== + +.. contents:: + +General information +=================== + +Q: How to get started? +---------------------- + +First, install__ F2PY. Then check that F2PY installation works +properly (see below__). Try out a `simple example`__. + +Read `F2PY Users Guide and Reference Manual`__. It contains lots +of complete examples. + +If you have any questions/problems when using F2PY, don't hesitate to +turn to `F2PY users mailing list`__ or directly to me. + +__ index.html#installation +__ #testing +__ index.html#usage +__ usersguide/index.html +__ index.html#mailing-list + +Q: When to report bugs? +----------------------- + +* If F2PY scanning fails on Fortran sources that otherwise compile + fine. + +* After checking that you have the latest version of F2PY from its + CVS. It is possible that a bug has been fixed already. See also the + log entries in the file `HISTORY.txt`_ (`HISTORY.txt in CVS`_). + +* After checking that your Python and Numerical Python installations + work correctly. + +* After checking that your C and Fortran compilers work correctly. + + +Q: How to report bugs? +---------------------- + +You can send bug reports directly to me. Please, include information +about your platform (operating system, version) and +compilers/linkers, e.g. the output (both stdout/stderr) of +:: + + python -c 'import f2py2e.diagnose;f2py2e.diagnose.run()' + +Feel free to add any other relevant information. However, avoid +sending the output of F2PY generated ``.pyf`` files (unless they are +manually modified) or any binary files like shared libraries or object +codes. + +While reporting bugs, you may find the following notes useful: + +* `How To Ask Questions The Smart Way`__ by E. S. Raymond and R. Moen. + +* `How to Report Bugs Effectively`__ by S. Tatham. + +__ http://www.catb.org/~esr/faqs/smart-questions.html +__ http://www.chiark.greenend.org.uk/~sgtatham/bugs.html + +Installation +============ + +Q: How to use F2PY with different Python versions? +-------------------------------------------------- + +Run the installation command using the corresponding Python +executable. For example, +:: + + python2.1 setup.py install + +installs the ``f2py`` script as ``f2py2.1``. + +See `Distutils User Documentation`__ for more information how to +install Python modules to non-standard locations. + +__ http://www.python.org/sigs/distutils-sig/doc/inst/inst.html + + +Q: Why F2PY is not working after upgrading? +------------------------------------------- + +If upgrading from F2PY version 2.3.321 or earlier then remove all f2py +specific files from ``/path/to/python/bin`` directory before +running installation command. + +Q: How to get/upgrade scipy_distutils when using F2PY from CVS? +--------------------------------------------------------------- + +To get scipy_distutils from SciPy CVS repository, run +:: + + cd cvs/f2py2e/ + make scipy_distutils + +This will checkout scipy_distutils to the current directory. + +You can upgrade scipy_distutils by executing +:: + + cd cvs/f2py2e/scipy_distutils + cvs update -Pd + +and install it by executing +:: + + cd cvs/f2py2e/scipy_distutils + python setup_scipy_distutils.py install + +In most of the time, f2py2e and scipy_distutils can be upgraded +independently. + +Testing +======= + +Q: How to test if F2PY is installed correctly? +---------------------------------------------- + +Run +:: + + f2py + +without arguments. If F2PY is installed correctly then it should print +the usage information for f2py. + +Q: How to test if F2PY is working correctly? +-------------------------------------------- + +For a quick test, try out an example problem from Usage__ +section in `README.txt`_. + +__ index.html#usage + +For running F2PY unit tests, see `TESTING.txt`_. + + +Q: How to run tests and examples in f2py2e/test-suite/ directory? +--------------------------------------------------------------------- + +You shouldn't. These tests are obsolete and I have no intention to +make them work. They will be removed in future. + + +Compiler/Platform-specific issues +================================= + +Q: What are supported platforms and compilers? +---------------------------------------------- + +F2PY is developed on Linux system with a GCC compiler (versions +2.95.x, 3.x). Fortran 90 related hooks are tested against Intel +Fortran Compiler. F2PY should work under any platform where Python and +Numeric are installed and has supported Fortran compiler installed. + +To see a list of supported compilers, execute:: + + f2py -c --help-fcompiler + +Example output:: + + List of available Fortran compilers: + --fcompiler=gnu GNU Fortran Compiler (3.3.4) + --fcompiler=intel Intel Fortran Compiler for 32-bit apps (8.0) + List of unavailable Fortran compilers: + --fcompiler=absoft Absoft Corp Fortran Compiler + --fcompiler=compaq Compaq Fortran Compiler + --fcompiler=compaqv DIGITAL|Compaq Visual Fortran Compiler + --fcompiler=hpux HP Fortran 90 Compiler + --fcompiler=ibm IBM XL Fortran Compiler + --fcompiler=intele Intel Fortran Compiler for Itanium apps + --fcompiler=intelev Intel Visual Fortran Compiler for Itanium apps + --fcompiler=intelv Intel Visual Fortran Compiler for 32-bit apps + --fcompiler=lahey Lahey/Fujitsu Fortran 95 Compiler + --fcompiler=mips MIPSpro Fortran Compiler + --fcompiler=nag NAGWare Fortran 95 Compiler + --fcompiler=pg Portland Group Fortran Compiler + --fcompiler=sun Sun|Forte Fortran 95 Compiler + --fcompiler=vast Pacific-Sierra Research Fortran 90 Compiler + List of unimplemented Fortran compilers: + --fcompiler=f Fortran Company/NAG F Compiler + For compiler details, run 'config_fc --verbose' setup command. + + +Q: How to use the F compiler in F2PY? +------------------------------------- + +Read `f2py2e/doc/using_F_compiler.txt`__. It describes why the F +compiler cannot be used in a normal way (i.e. using ``-c`` switch) to +build F2PY generated modules. It also gives a workaround to this +problem. + +__ http://cens.ioc.ee/cgi-bin/viewcvs.cgi/python/f2py2e/doc/using_F_compiler.txt?rev=HEAD&content-type=text/vnd.viewcvs-markup + +Q: How to use F2PY under Windows? +--------------------------------- + +F2PY can be used both within Cygwin__ and MinGW__ environments under +Windows, F2PY can be used also in Windows native terminal. +See the section `Setting up environment`__ for Cygwin and MinGW. + +__ http://cygwin.com/ +__ http://www.mingw.org/ +__ http://cens.ioc.ee/~pearu/scipy/BUILD_WIN32.html#setting-up-environment + +Install scipy_distutils and F2PY. Win32 installers of these packages +are provided in `F2PY Download`__ section. + +__ http://cens.ioc.ee/projects/f2py2e/#download + +Use ``--compiler=`` and ``--fcompiler`` F2PY command line switches to +to specify which C and Fortran compilers F2PY should use, respectively. + +Under MinGW environment, ``mingw32`` is default for a C compiler. + +Supported and Unsupported Features +================================== + +Q: Does F2PY support ``ENTRY`` statements? +------------------------------------------ + +Yes, starting at F2PY version higher than 2.39.235_1706. + +Q: Does F2PY support derived types in F90 code? +----------------------------------------------- + +Not yet. However I do have plans to implement support for F90 TYPE +constructs in future. But note that the task in non-trivial and may +require the next edition of F2PY for which I don't have resources to +work with at the moment. + +Jeffrey Hagelberg from LLNL has made progress on adding +support for derived types to f2py. He writes: + + At this point, I have a version of f2py that supports derived types + for most simple cases. I have multidimensional arrays of derived + types and allocatable arrays of derived types working. I'm just now + starting to work on getting nested derived types to work. I also + haven't tried putting complex number in derived types yet. + +Hopefully he can contribute his changes to f2py soon. + +Q: Does F2PY support pointer data in F90 code? +----------------------------------------------- + +No. I have never needed it and I haven't studied if there are any +obstacles to add pointer data support to F2PY. + +Q: What if Fortran 90 code uses ``<type spec>(kind=KIND(..))``? +--------------------------------------------------------------- + +Currently, F2PY can handle only ``<type spec>(kind=<kindselector>)`` +declarations where ``<kindselector>`` is a numeric integer (e.g. 1, 2, +4,...) but not a function call ``KIND(..)`` or any other +expression. F2PY needs to know what would be the corresponding C type +and a general solution for that would be too complicated to implement. + +However, F2PY provides a hook to overcome this difficulty, namely, +users can define their own <Fortran type> to <C type> maps. For +example, if Fortran 90 code contains:: + + REAL(kind=KIND(0.0D0)) ... + +then create a file ``.f2py_f2cmap`` (into the working directory) +containing a Python dictionary:: + + {'real':{'KIND(0.0D0)':'double'}} + +for instance. + +Or more generally, the file ``.f2py_f2cmap`` must contain a dictionary +with items:: + + <Fortran typespec> : {<selector_expr>:<C type>} + +that defines mapping between Fortran type:: + + <Fortran typespec>([kind=]<selector_expr>) + +and the corresponding ``<C type>``. ``<C type>`` can be one of the +following:: + + char + signed_char + short + int + long_long + float + double + long_double + complex_float + complex_double + complex_long_double + string + +For more information, see ``f2py2e/capi_maps.py``. + +Related software +================ + +Q: How F2PY distinguishes from Pyfort? +-------------------------------------- + +F2PY and Pyfort have very similar aims and ideology of how they are +targeted. Both projects started to evolve in the same year 1999 +independently. When we discovered each others projects, a discussion +started to join the projects but that unfortunately failed for +various reasons, e.g. both projects had evolved too far that merging +the tools would have been impractical and giving up the efforts that +the developers of both projects have made was unacceptable to both +parties. And so, nowadays we have two tools for connecting Fortran +with Python and this fact will hardly change in near future. To decide +which one to choose is a matter of taste, I can only recommend to try +out both to make up your choice. + +At the moment F2PY can handle more wrapping tasks than Pyfort, +e.g. with F2PY one can wrap Fortran 77 common blocks, Fortran 90 +module routines, Fortran 90 module data (including allocatable +arrays), one can call Python from Fortran, etc etc. F2PY scans Fortran +codes to create signature (.pyf) files. F2PY is free from most of the +limitations listed in in `the corresponding section of Pyfort +Reference Manual`__. + +__ http://pyfortran.sourceforge.net/pyfort/pyfort_reference.htm#pgfId-296925 + +There is a conceptual difference on how F2PY and Pyfort handle the +issue of different data ordering in Fortran and C multi-dimensional +arrays. Pyfort generated wrapper functions have optional arguments +TRANSPOSE and MIRROR that can be used to control explicitly how the array +arguments and their dimensions are passed to Fortran routine in order +to deal with the C/Fortran data ordering issue. F2PY generated wrapper +functions hide the whole issue from an end-user so that translation +between Fortran and C/Python loops and array element access codes is +one-to-one. How the F2PY generated wrappers deal with the issue is +determined by a person who creates a signature file via using +attributes like ``intent(c)``, ``intent(copy|overwrite)``, +``intent(inout|in,out|inplace)`` etc. + +For example, let's consider a typical usage of both F2PY and Pyfort +when wrapping the following simple Fortran code: + +.. include:: simple.f + :literal: + +The comment lines starting with ``cf2py`` are read by F2PY (so that we +don't need to generate/handwrite an intermediate signature file in +this simple case) while for a Fortran compiler they are just comment +lines. + +And here is a Python version of the Fortran code: + +.. include:: pytest.py + :literal: + +To generate a wrapper for subroutine ``foo`` using F2PY, execute:: + + $ f2py -m f2pytest simple.f -c + +that will generate an extension module ``f2pytest`` into the current +directory. + +To generate a wrapper using Pyfort, create the following file + +.. include:: pyforttest.pyf + :literal: + +and execute:: + + $ pyfort pyforttest + +In Pyfort GUI add ``simple.f`` to the list of Fortran sources and +check that the signature file is in free format. And then copy +``pyforttest.so`` from the build directory to the current directory. + +Now, in Python + +.. include:: simple_session.dat + :literal: + +Q: Can Pyfort .pyf files used with F2PY and vice versa? +------------------------------------------------------- + +After some simple modifications, yes. You should take into account the +following differences in Pyfort and F2PY .pyf files. + ++ F2PY signature file contains ``python module`` and ``interface`` + blocks that are equivalent to Pyfort ``module`` block usage. + ++ F2PY attribute ``intent(inplace)`` is equivalent to Pyfort + ``intent(inout)``. F2PY ``intent(inout)`` is a strict (but safe) + version of ``intent(inplace)``, any mismatch in arguments with + expected type, size, or contiguouness will trigger an exception + while ``intent(inplace)`` (dangerously) modifies arguments + attributes in-place. + +Misc +==== + +Q: How to establish which Fortran compiler F2PY will use? +--------------------------------------------------------- + +This question may be releavant when using F2PY in Makefiles. Here +follows a script demonstrating how to determine which Fortran compiler +and flags F2PY will use:: + + # Using post-0.2.2 scipy_distutils + from scipy_distutils.fcompiler import new_fcompiler + compiler = new_fcompiler() # or new_fcompiler(compiler='intel') + compiler.dump_properties() + + # Using pre-0.2.2 scipy_distutils + import os + from scipy_distutils.command.build_flib import find_fortran_compiler + def main(): + fcompiler = os.environ.get('FC_VENDOR') + fcompiler_exec = os.environ.get('F77') + f90compiler_exec = os.environ.get('F90') + fc = find_fortran_compiler(fcompiler, + fcompiler_exec, + f90compiler_exec, + verbose = 0) + print 'FC=',fc.f77_compiler + print 'FFLAGS=',fc.f77_switches + print 'FOPT=',fc.f77_opt + if __name__ == "__main__": + main() + +Users feedback +============== + +Q: Where to find additional information on using F2PY? +------------------------------------------------------ + +There are several F2PY related tutorials, slides, papers, etc +available: + ++ `Fortran to Python Interface Generator with an Application to + Aerospace Engineering`__ by P. Peterson, J. R. R. A. Martins, and + J. J. Alonso in `In Proceedings of the 9th International Python + Conference`__, Long Beach, California, 2001. + +__ http://www.python9.org/p9-cdrom/07/index.htm +__ http://www.python9.org/ + ++ Section `Adding Fortran90 code`__ in the UG of `The Bolometer Data + Analysis Project`__. + +__ http://www.astro.rub.de/laboca/download/boa_master_doc/7_4Adding_Fortran90_code.html +__ http://www.openboa.de/ + ++ Powerpoint presentation `Python for Scientific Computing`__ by Eric + Jones in `The Ninth International Python Conference`__. + +__ http://www.python9.org/p9-jones.ppt +__ http://www.python9.org/ + ++ Paper `Scripting a Large Fortran Code with Python`__ by Alvaro Caceres + Calleja in `International Workshop on Software Engineering for High + Performance Computing System Applications`__. + +__ http://csdl.ics.hawaii.edu/se-hpcs/pdf/calleja.pdf +__ http://csdl.ics.hawaii.edu/se-hpcs/ + ++ Section `Automatic building of C/Fortran extension for Python`__ by + Simon Lacoste-Julien in `Summer 2002 Report about Hybrid Systems + Modelling`__. + +__ http://moncs.cs.mcgill.ca/people/slacoste/research/report/SummerReport.html#tth_sEc3.4 +__ http://moncs.cs.mcgill.ca/people/slacoste/research/report/SummerReport.html + ++ `Scripting for Computational Science`__ by Hans Petter Langtangen + (see the `Mixed language programming`__ and `NumPy array programming`__ + sections for examples on using F2PY). + +__ http://www.ifi.uio.no/~inf3330/lecsplit/ +__ http://www.ifi.uio.no/~inf3330/lecsplit/slide662.html +__ http://www.ifi.uio.no/~inf3330/lecsplit/slide718.html + ++ Chapters 5 and 9 of `Python Scripting for Computational Science`__ + by H. P. Langtangen for case studies on using F2PY. + +__ http://www.springeronline.com/3-540-43508-5 + ++ Section `Fortran Wrapping`__ in `Continuity`__, a computational tool + for continuum problems in bioengineering and physiology. + +__ http://www.continuity.ucsd.edu/cont6_html/docs_fram.html +__ http://www.continuity.ucsd.edu/ + ++ Presentation `PYFORT and F2PY: 2 ways to bind C and Fortran with Python`__ + by Reiner Vogelsang. + +__ http://www.prism.enes.org/WPs/WP4a/Slides/pyfort/pyfort.html + ++ Lecture slides of `Extending Python: speed it up`__. + +__ http://www.astro.uni-bonn.de/~heith/lecture_pdf/friedrich5.pdf + ++ Wiki topics on `Wrapping Tools`__ and `Wrapping Bemchmarks`__ for Climate + System Center at the University of Chicago. + +__ https://geodoc.uchicago.edu/climatewiki/DiscussWrappingTools +__ https://geodoc.uchicago.edu/climatewiki/WrappingBenchmarks + ++ `Performance Python with Weave`__ by Prabhu Ramachandran. + +__ http://www.scipy.org/documentation/weave/weaveperformance.html + ++ `How To Install py-f2py on Mac OSX`__ + +__ http://py-f2py.darwinports.com/ + +Please, let me know if there are any other sites that document F2PY +usage in one or another way. + +Q: What projects use F2PY? +-------------------------- + ++ `SciPy: Scientific tools for Python`__ + +__ http://www.scipy.org/ + ++ `The Bolometer Data Analysis Project`__ + +__ http://www.openboa.de/ + ++ `pywavelet`__ + +__ http://www.met.wau.nl/index.html?http://www.met.wau.nl/medewerkers/moenea/python/pywavelet.html + ++ `PyARTS: an ARTS related Python package`__. + +__ http://www.met.ed.ac.uk/~cory/PyARTS/ + ++ `Python interface to PSPLINE`__, a collection of Spline and + Hermite interpolation tools for 1D, 2D, and 3D datasets on + rectilinear grids. + +__ http://pypspline.sourceforge.net + ++ `Markovian Analysis Package for Python`__. + +__ http://pymc.sourceforge.net + ++ `Modular toolkit for Data Processing (MDP)`__ + +__ http://mdp-toolkit.sourceforge.net/ + + +Please, send me a note if you are using F2PY in your project. + +Q: What people think about F2PY? +-------------------------------- + +*F2PY is GOOD*: + +Here are some comments people have posted to f2py mailing list and c.l.py: + ++ Ryan Krauss: I really appreciate f2py. It seems weird to say, but I + am excited about relearning FORTRAN to compliment my python stuff. + ++ Fabien Wahl: f2py is great, and is used extensively over here... + ++ Fernando Perez: Anyway, many many thanks for this amazing tool. + + I haven't used pyfort, but I can definitely vouch for the amazing quality of + f2py. And since f2py is actively used by scipy, it won't go unmaintained. + It's quite impressive, and very easy to use. + ++ Kevin Mueller: First off, thanks to those responsible for F2PY; + its been an integral tool of my research for years now. + ++ David Linke: Best regards and thanks for the great tool! + ++ Perrin Meyer: F2Py is really useful! + ++ Hans Petter Langtangen: First of all, thank you for developing + F2py. This is a very important contribution to the scientific + computing community. We are using F2py a lot and are very happy with + it. + ++ Berthold Höllmann: Thank's alot. It seems it is also working in my + 'real' application :-) + ++ John Hunter: At first I wrapped them with f2py (unbelievably easy!)... + ++ Cameron Laird: Among many other features, Python boasts a mature + f2py, which makes it particularly rewarding to yoke Fortran- and + Python-coded modules into finished applications. + ++ Ryan Gutenkunst: f2py is sweet magic. + +*F2PY is BAD*: + ++ `Is it worth using on a large scale python drivers for Fortran + subroutines, interfaced with f2py?`__ + +__ http://sepwww.stanford.edu/internal/computing/python.html + +Additional comments on F2PY, good or bad, are welcome! + +.. References: +.. _README.txt: index.html +.. _HISTORY.txt: HISTORY.html +.. _HISTORY.txt in CVS: http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt?rev=HEAD&content-type=text/x-cvsweb-markup +.. _TESTING.txt: TESTING.html diff --git a/numpy/f2py/docs/HISTORY.txt b/numpy/f2py/docs/HISTORY.txt new file mode 100644 index 000000000..876ab2362 --- /dev/null +++ b/numpy/f2py/docs/HISTORY.txt @@ -0,0 +1,1044 @@ +.. -*- rest -*- + +========================= + F2PY History +========================= + +:Author: Pearu Peterson <pearu@cens.ioc.ee> +:Web-site: http://cens.ioc.ee/projects/f2py2e/ +:Date: $Date: 2005/09/16 08:36:45 $ +:Revision: $Revision: 1.191 $ + +.. Contents:: + +Release 2.46.243 +===================== + +* common_rules.py + + - Fixed compiler warnings. + +* fortranobject.c + + - Fixed another dims calculation bug. + - Fixed dims calculation bug and added the corresponding check. + - Accept higher dimensional arrays if their effective rank matches. + Effective rank is multiplication of non-unit dimensions. + +* f2py2e.py + + - Added support for scipy.distutils version 0.4.0. + +* Documentation + + - Added example about ``intent(callback,hide)`` usage. Updates. + - Updated FAQ. + +* cb_rules.py + + - Fixed missing need kw error. + - Fixed getting callback non-existing extra arguments. + - External callback functions and extra_args can be set via + ext.module namespace. + - Avoid crash when external callback function is not set. + +* rules.py + + - Enabled ``intent(out)`` for ``intent(aux)`` non-complex scalars. + - Fixed splitting lines in F90 fixed form mode. + - Fixed FORTRANAME typo, relevant when wrapping scalar functions with + ``--no-wrap-functions``. + - Improved failure handling for callback functions. + - Fixed bug in writting F90 wrapper functions when a line length + is exactly 66. + +* cfuncs.py + + - Fixed dependency issue with typedefs. + - Introduced ``-DUNDERSCORE_G77`` that cause extra underscore to be + used for external names that contain an underscore. + +* capi_maps.py + + - Fixed typos. + - Fixed using complex cb functions. + +* crackfortran.py + + - Introduced parent_block key. Get ``use`` statements recursively + from parent blocks. + - Apply parameter values to kindselectors. + - Fixed bug evaluating ``selected_int_kind`` function. + - Ignore Name and Syntax errors when evaluating scalars. + - Treat ``<int>_intType`` as ``<int>`` in get_parameters. + - Added support for F90 line continuation in fix format mode. + - Include optional attribute of external to signature file. + - Add ``entry`` arguments to variable lists. + - Treat \xa0 character as space. + - Fixed bug where __user__ callback subroutine was added to its + argument list. + - In strict 77 mode read only the first 72 columns. + - Fixed parsing ``v(i) = func(r)``. + - Fixed parsing ``integer*4::``. + - Fixed parsing ``1.d-8`` when used as a parameter value. + +Release 2.45.241_1926 +===================== + +* diagnose.py + + - Clean up output. + +* cb_rules.py + + - Fixed ``_cpointer`` usage for subroutines. + - Fortran function ``_cpointer`` can be used for callbacks. + +* func2subr.py + + - Use result name when wrapping functions with subroutines. + +* f2py2e.py + + - Fixed ``--help-link`` switch. + - Fixed ``--[no-]lower`` usage with ``-c`` option. + - Added support for ``.pyf.src`` template files. + +* __init__.py + + - Using ``exec_command`` in ``compile()``. + +* setup.py + + - Clean up. + - Disabled ``need_scipy_distutils`` function. From now on it is assumed + that proper version of ``scipy_distutils`` is already installed. + +* capi_maps.py + + - Added support for wrapping unsigned integers. In a .pyf file + ``integer(-1)``, ``integer(-2)``, ``integer(-4)`` correspond to + ``unsigned char``, ``unsigned short``, ``unsigned`` C types, + respectively. + +* tests/c/return_real.py + + - Added tests to wrap C functions returning float/double. + +* fortranobject.c + + - Added ``_cpointer`` attribute to wrapped objects. + +* rules.py + + - ``_cpointer`` feature for wrapped module functions is not + functional at the moment. + - Introduced ``intent(aux)`` attribute. Useful to save a value + of a parameter to auxiliary C variable. Note that ``intent(aux)`` + implies ``intent(c)``. + - Added ``usercode`` section. When ``usercode`` is used in ``python + module`` block twise then the contents of the second multi-line + block is inserted after the definition of external routines. + - Call-back function arguments can be CObjects. + +* cfuncs.py + + - Allow call-back function arguments to be fortran objects. + - Allow call-back function arguments to be built-in functions. + +* crackfortran.py + + - Fixed detection of a function signature from usage example. + - Cleaned up -h output for intent(callback) variables. + - Repair malformed argument list (missing argument name). + - Warn on the usage of multiple attributes without type specification. + - Evaluate only scalars ``<initexpr>`` (e.g. not of strings). + - Evaluate ``<initexpr>`` using parameters name space. + - Fixed resolving `<name>(<args>)[result(<result>)]` pattern. + - ``usercode`` can be used more than once in the same context. + +Release 2.43.239_1831 +===================== + +* auxfuncs.py + + - Made ``intent(in,inplace)`` to mean ``intent(inplace)``. + +* f2py2e.py + + - Intoduced ``--help-link`` and ``--link-<resource>`` + switches to link generated extension module with system + ``<resource>`` as defined by scipy_distutils/system_info.py. + +* fortranobject.c + + - Patch to make PyArray_CanCastSafely safe on 64-bit machines. + Fixes incorrect results when passing ``array('l')`` to + ``real*8 intent(in,out,overwrite)`` arguments. + +* rules.py + + - Avoid empty continuation lines in Fortran wrappers. + +* cfuncs.py + + - Adding ``\0`` at the end of a space-padded string, fixes tests + on 64-bit Gentoo. + +* crackfortran.py + + - Fixed splitting lines with string parameters. + +Release 2.43.239_1806 +===================== + +* Tests + + - Fixed test site that failed after padding strings with spaces + instead of zeros. + +* Documentation + + - Documented ``intent(inplace)`` attribute. + - Documented ``intent(callback)`` attribute. + - Updated FAQ, added Users Feedback section. + +* cfuncs.py + + - Padding longer (than provided from Python side) strings with spaces + (that is Fortran behavior) instead of nulls (that is C strncpy behavior). + +* f90mod_rules.py + + - Undoing rmbadnames in Python and Fortran layers. + +* common_rules.py + + - Renaming common block items that have names identical to C keywords. + - Fixed wrapping blank common blocks. + +* fortranobject.h + + - Updated numarray (0.9, 1.0, 1.1) support (patch by Todd Miller). + +* fortranobject.c + + - Introduced ``intent(inplace)`` feature. + - Fix numarray reference counts (patch by Todd). + - Updated numarray (0.9, 1.0, 1.1) support (patch by Todd Miller). + - Enabled F2PY_REPORT_ON_ARRAY_COPY for Numarray. + +* capi_maps.py + + - Always normalize .f2py_f2cmap keys to lower case. + +* rules.py + + - Disabled ``index`` macro as it conflicts with the one defined + in string.h. + - Moved ``externroutines`` up to make it visible to ``usercode``. + - Fixed bug in f90 code generation: no empty line continuation is + allowed. + - Fixed undefined symbols failure when ``fortranname`` is used + to rename a wrapped function. + - Support for ``entry`` statement. + +* auxfuncs.py + + - Made is* functions more robust with respect to parameters that + have no typespec specified. + - Using ``size_t`` instead of ``int`` as the type of string + length. Fixes issues on 64-bit platforms. + +* setup.py + + - Fixed bug of installing ``f2py`` script as ``.exe`` file. + +* f2py2e.py + + - ``--compiler=`` and ``--fcompiler=`` can be specified at the same time. + +* crackfortran.py + + - Fixed dependency detection for non-intent(in|inout|inplace) arguments. + They must depend on their dimensions, not vice-versa. + - Don't match ``!!f2py`` as a start of f2py directive. + - Only effective intent attributes will be output to ``-h`` target. + - Introduced ``intent(callback)`` to build interface between Python + functions and Fortran external routines. + - Avoid including external arguments to __user__ modules. + - Initial hooks to evaluate ``kind`` and ``selected_int_kind``. + - Evaluating parameters in {char,kind}selectors and applying rmbadname. + - Evaluating parameters using also module parameters. Fixed the order + of parameter evaluation. + - Fixed silly bug: when block name was not lower cased, it was not + recognized correctly. + - Applying mapping '.false.'->'False', '.true.'->'True' to logical + parameters. TODO: Support for logical expressions is needed. + - Added support for multiple statements in one line (separated with semicolon). + - Impl. get_useparameters function for using parameter values from + other f90 modules. + - Applied Bertholds patch to fix bug in evaluating expressions + like ``1.d0/dvar``. + - Fixed bug in reading string parameters. + - Evaluating parameters in charselector. Code cleanup. + - Using F90 module parameters to resolve kindselectors. + - Made the evaluation of module data init-expression more robust. + - Support for ``entry`` statement. + - Fixed ``determineexprtype`` that in the case of parameters + returned non-dictionary objects. + - Use ``-*- fix -*-`` to specify that a file is in fixed format. + +Release 2.39.235_1693 +===================== + +* fortranobject.{h,c} + + - Support for allocatable string arrays. + +* cfuncs.py + + - Call-back arguments can now be also instances that have ``__call__`` method + as well as instance methods. + +* f2py2e.py + + - Introduced ``--include_paths <path1>:<path2>:..`` command line + option. + - Added ``--compiler=`` support to change the C/C++ compiler from + f2py command line. + +* capi_maps.py + + - Handle ``XDY`` parameter constants. + +* crackfortran.py + + - Handle ``XDY`` parameter constants. + + - Introduced formatpattern to workaround a corner case where reserved + keywords are used in format statement. Other than that, format pattern + has no use. + + - Parameters are now fully evaluated. + +* More splitting of documentation strings. + +* func2subr.py - fixed bug for function names that f77 compiler + would set ``integer`` type. + +Release 2.39.235_1660 +===================== + +* f2py2e.py + + - Fixed bug in using --f90flags=.. + +* f90mod_rules.py + + - Splitted generated documentation strings (to avoid MSVC issue when + string length>2k) + + - Ignore ``private`` module data. + +Release 2.39.235_1644 +===================== + +:Date:24 February 2004 + +* Character arrays: + + - Finished complete support for character arrays and arrays of strings. + - ``character*n a(m)`` is treated like ``character a(m,n)`` with ``intent(c)``. + - Character arrays are now considered as ordinary arrays (not as arrays + of strings which actually didn't work). + +* docs + + - Initial f2py manpage file f2py.1. + - Updated usersguide and other docs when using scipy_distutils 0.2.2 + and up. + +* capi_maps.py + + - Try harder to use .f2py_f2cmap mappings when kind is used. + +* crackfortran.py + + - Included files are first search in the current directory and + then from the source file directory. + - Ignoring dimension and character selector changes. + - Fixed bug in Fortran 90 comments of fixed format. + - Warn when .pyf signatures contain undefined symbols. + - Better detection of source code formats. Using ``-*- fortran -*-`` + or ``-*- f90 -*-`` in the first line of a Fortran source file is + recommended to help f2py detect the format, fixed or free, + respectively, correctly. + +* cfuncs.py + + - Fixed intent(inout) scalars when typecode=='l'. + - Fixed intent(inout) scalars when not using numarray. + - Fixed intent(inout) scalars when using numarray. + +* diagnose.py + + - Updated for scipy_distutils 0.2.2 and up. + - Added numarray support to diagnose. + +* fortranobject.c + + - Fixed nasty bug with intent(in,copy) complex slice arrays. + - Applied Todd's patch to support numarray's byteswapped or + misaligned arrays, requires numarray-0.8 or higher. + +* f2py2e.py + + - Applying new hooks for scipy_distutils 0.2.2 and up, keeping + backward compatibility with depreciation messages. + - Using always os.system on non-posix platforms in f2py2e.compile + function. + +* rules.py + + - Changed the order of buildcallback and usercode junks. + +* setup.cfg + + - Added so that docs/ and tests/ directories are included to RPMs. + +* setup.py + + - Installing f2py.py instead of f2py.bat under NT. + - Introduced ``--with-scipy_distutils`` that is useful when making + f2py tar-ball with scipy_distutils included. + +Release 2.37.233-1545 +===================== + +:Date: 11 September 2003 + +* rules.py + + - Introduced ``interface_usercode`` replacement. When ``usercode`` + statement is used inside the first interface block, its contents + will be inserted at the end of initialization function of a F2PY + generated extension module (feature request: Berthold Höllmann). + - Introduced auxiliary function ``as_column_major_storage`` that + converts input array to an array with column major storage order + (feature request: Hans Petter Langtangen). + +* crackfortran.py + + - Introduced ``pymethoddef`` statement. + +* cfuncs.py + + - Fixed "#ifdef in #define TRYPYARRAYTEMPLATE" bug (patch thanks + to Bernhard Gschaider) + +* auxfuncs.py + + - Introduced ``getpymethod`` function. + - Enabled multi-line blocks in ``callprotoargument`` statement. + +* f90mod_rules.py + + - Undone "Fixed Warning 43 emitted by Intel Fortran compiler" that + causes (curios) segfaults. + +* fortranobject.c + + - Fixed segfaults (that were introduced with recent memory leak + fixes) when using allocatable arrays. + - Introduced F2PY_REPORT_ON_ARRAY_COPY CPP macro int-variable. If defined + then a message is printed to stderr whenever a copy of an array is + made and arrays size is larger than F2PY_REPORT_ON_ARRAY_COPY. + +Release 2.35.229-1505 +===================== + +:Date: 5 August 2003 + +* General + + - Introduced ``usercode`` statement (dropped ``c_code`` hooks). + +* setup.py + + - Updated the CVS location of scipy_distutils. + +* auxfuncs.py + + - Introduced ``isint1array(var)`` for fixing ``integer*1 intent(out)`` + support. + +* tests/f77/callback.py + + Introduced some basic tests. + +* src/fortranobject.{c,h} + + - Fixed memory leaks when getting/setting allocatable arrays. + (Bug report by Bernhard Gschaider) + + - Initial support for numarray (Todd Miller's patch). Use -DNUMARRAY + on the f2py command line to enable numarray support. Note that + there is no character arrays support and these hooks are not + tested with F90 compilers yet. + +* cfuncs.py + + - Fixed reference counting bug that appeared when constructing extra + argument list to callback functions. + - Added ``PyArray_LONG != PyArray_INT`` test. + +* f2py2e.py + + Undocumented ``--f90compiler``. + +* crackfortran.py + + - Introduced ``usercode`` statement. + - Fixed newlines when outputting multi-line blocks. + - Optimized ``getlincoef`` loop and ``analyzevars`` for cases where + len(vars) is large. + - Fixed callback string argument detection. + - Fixed evaluating expressions: only int|float expressions are + evaluated succesfully. + +* docs + + Documented -DF2PY_REPORT_ATEXIT feature. + +* diagnose.py + + Added CPU information and sys.prefix printout. + +* tests/run_all.py + + Added cwd to PYTHONPATH. + +* tests/f??/return_{real,complex}.py + + Pass "infinity" check in SunOS. + +* rules.py + + - Fixed ``integer*1 intent(out)`` support + - Fixed free format continuation of f2py generated F90 files. + +* tests/mixed/ + + Introduced tests for mixing Fortran 77, Fortran 90 fixed and free + format codes in one module. + +* f90mod_rules.py + + - Fixed non-prototype warnings. + - Fixed Warning 43 emitted by Intel Fortran compiler. + - Avoid long lines in Fortran codes to reduce possible problems with + continuations of lines. + +Public Release 2.32.225-1419 +============================ + +:Date: 8 December 2002 + +* docs/usersguide/ + + Complete revision of F2PY Users Guide + +* tests/run_all.py + + - New file. A Python script to run all f2py unit tests. + +* Removed files: buildmakefile.py, buildsetup.py. + +* tests/f77/ + + - Added intent(out) scalar tests. + +* f2py_testing.py + + - Introduced. It contains jiffies, memusage, run, cmdline functions + useful for f2py unit tests site. + +* setup.py + + - Install scipy_distutils only if it is missing or is too old + for f2py. + +* f90modrules.py + + - Fixed wrapping f90 module data. + - Fixed wrapping f90 module subroutines. + - Fixed f90 compiler warnings for wrapped functions by using interface + instead of external stmt for functions. + +* tests/f90/ + + - Introduced return_*.py tests. + +* func2subr.py + + - Added optional signature argument to createfuncwrapper. + - In f2pywrappers routines, declare external, scalar, remaining + arguments in that order. Fixes compiler error 'Invalid declaration' + for:: + + real function foo(a,b) + integer b + real a(b) + end + +* crackfortran.py + + - Removed first-line comment information support. + - Introduced multiline block. Currently usable only for + ``callstatement`` statement. + - Improved array length calculation in getarrlen(..). + - "From sky" program group is created only if ``groupcounter<1``. + See TODO.txt. + - Added support for ``dimension(n:*)``, ``dimension(*:n)``. They are + treated as ``dimesnion(*)`` by f2py. + - Fixed parameter substitution (this fixes TODO item by Patrick + LeGresley, 22 Aug 2001). + +* f2py2e.py + + - Disabled all makefile, setup, manifest file generation hooks. + - Disabled --[no]-external-modroutines option. All F90 module + subroutines will have Fortran/C interface hooks. + - --build-dir can be used with -c option. + - only/skip modes can be used with -c option. + - Fixed and documented `-h stdout` feature. + - Documented extra options. + - Introduced --quiet and --verbose flags. + +* cb_rules.py + + - Fixed debugcapi hooks for intent(c) scalar call-back arguments + (bug report: Pierre Schnizer). + - Fixed intent(c) for scalar call-back arguments. + - Improved failure reports. + +* capi_maps.py + + - Fixed complex(kind=..) to C type mapping bug. The following hold + complex==complex(kind=4)==complex*8, complex(kind=8)==complex*16 + - Using signed_char for integer*1 (bug report: Steve M. Robbins). + - Fixed logical*8 function bug: changed its C correspondence to + long_long. + - Fixed memory leak when returning complex scalar. + +* __init__.py + + - Introduced a new function (for f2py test site, but could be useful + in general) ``compile(source[,modulename,extra_args])`` for + compiling fortran source codes directly from Python. + +* src/fortranobject.c + + - Multi-dimensional common block members and allocatable arrays + are returned as Fortran-contiguous arrays. + - Fixed NULL return to Python without exception. + - Fixed memory leak in getattr(<fortranobj>,'__doc__'). + - <fortranobj>.__doc__ is saved to <fortranobj>.__dict__ (previously + it was generated each time when requested). + - Fixed a nasty typo from the previous item that caused data + corruption and occasional SEGFAULTs. + - array_from_pyobj accepts arbitrary rank arrays if the last dimension + is undefined. E.g. dimension(3,*) accepts a(3,4,5) and the result is + array with dimension(3,20). + - Fixed (void*) casts to make g++ happy (bug report: eric). + - Changed the interface of ARR_IS_NULL macro to avoid "``NULL used in + arithmetics``" warnings from g++. + +* src/fortranobject.h + + - Undone previous item. Defining NO_IMPORT_ARRAY for + src/fortranobject.c (bug report: travis) + - Ensured that PY_ARRAY_UNIQUE_SYMBOL is defined only for + src/fortranobject.c (bug report: eric). + +* rules.py + + - Introduced dummy routine feature. + - F77 and F90 wrapper subroutines (if any) as saved to different + files, <modulename>-f2pywrappers.f and <modulename>-f2pywrappers2.f90, + respectively. Therefore, wrapping F90 requires scipy_distutils >= + 0.2.0_alpha_2.229. + - Fixed compiler warnings about meaningless ``const void (*f2py_func)(..)``. + - Improved error messages for ``*_from_pyobj``. + - Changed __CPLUSPLUS__ macros to __cplusplus (bug report: eric). + - Changed (void*) casts to (f2py_init_func) (bug report: eric). + - Removed unnecessary (void*) cast for f2py_has_column_major_storage + in f2py_module_methods definition (bug report: eric). + - Changed the interface of f2py_has_column_major_storage function: + removed const from the 1st argument. + +* cfuncs.py + + - Introduced -DPREPEND_FORTRAN. + - Fixed bus error on SGI by using PyFloat_AsDouble when ``__sgi`` is defined. + This seems to be `know bug`__ with Python 2.1 and SGI. + - string_from_pyobj accepts only arrays whos elements size==sizeof(char). + - logical scalars (intent(in),function) are normalized to 0 or 1. + - Removed NUMFROMARROBJ macro. + - (char|short)_from_pyobj now use int_from_pyobj. + - (float|long_double)_from_pyobj now use double_from_pyobj. + - complex_(float|long_double)_from_pyobj now use complex_double_from_pyobj. + - Rewrote ``*_from_pyobj`` to be more robust. This fixes segfaults if + getting * from a string. Note that int_from_pyobj differs + from PyNumber_Int in that it accepts also complex arguments + (takes the real part) and sequences (takes the 1st element). + - Removed unnecessary void* casts in NUMFROMARROBJ. + - Fixed casts in ``*_from_pyobj`` functions. + - Replaced CNUMFROMARROBJ with NUMFROMARROBJ. + +.. __: http://sourceforge.net/tracker/index.php?func=detail&aid=435026&group_id=5470&atid=105470 + +* auxfuncs.py + + - Introduced isdummyroutine(). + - Fixed islong_* functions. + - Fixed isintent_in for intent(c) arguments (bug report: Pierre Schnizer). + - Introduced F2PYError and throw_error. Using throw_error, f2py + rejects illegal .pyf file constructs that otherwise would cause + compilation failures or python crashes. + - Fixed islong_long(logical*8)->True. + - Introduced islogical() and islogicalfunction(). + - Fixed prototype string argument (bug report: eric). + +* Updated README.txt and doc strings. Starting to use docutils. + +* Speed up for ``*_from_pyobj`` functions if obj is a sequence. + +* Fixed SegFault (reported by M.Braun) due to invalid ``Py_DECREF`` + in ``GETSCALARFROMPYTUPLE``. + +Older Releases +============== + +:: + + *** Fixed missing includes when wrapping F90 module data. + *** Fixed typos in docs of build_flib options. + *** Implemented prototype calculator if no callstatement or + callprotoargument statements are used. A warning is issued if + callstatement is used without callprotoargument. + *** Fixed transposing issue with array arguments in callback functions. + *** Removed -pyinc command line option. + *** Complete tests for Fortran 77 functions returning scalars. + *** Fixed returning character bug if --no-wrap-functions. + *** Described how to wrap F compiled Fortran F90 module procedures + with F2PY. See doc/using_F_compiler.txt. + *** Fixed the order of build_flib options when using --fcompiler=... + *** Recognize .f95 and .F95 files as Fortran sources with free format. + *** Cleaned up the output of 'f2py -h': removed obsolete items, + added build_flib options section. + *** Added --help-compiler option: it lists available Fortran compilers + as detected by scipy_distutils/command/build_flib.py. This option + is available only with -c option. + + +:Release: 2.13.175-1250 +:Date: 4 April 2002 + +:: + + *** Fixed copying of non-contigious 1-dimensional arrays bug. + (Thanks to Travis O.). + + +:Release: 2.13.175-1242 +:Date: 26 March 2002 + +:: + + *** Fixed ignoring type declarations. + *** Turned F2PY_REPORT_ATEXIT off by default. + *** Made MAX,MIN macros available by default so that they can be + always used in signature files. + *** Disabled F2PY_REPORT_ATEXIT for FreeBSD. + + +:Release: 2.13.175-1233 +:Date: 13 March 2002 + +:: + + *** Fixed Win32 port when using f2py.bat. (Thanks to Erik Wilsher). + *** F2PY_REPORT_ATEXIT is disabled for MACs. + *** Fixed incomplete dependency calculator. + + +:Release: 2.13.175-1222 +:Date: 3 March 2002 + +:: + + *** Plugged a memory leak for intent(out) arrays with overwrite=0. + *** Introduced CDOUBLE_to_CDOUBLE,.. functions for copy_ND_array. + These cast functions probably work incorrectly in Numeric. + + +:Release: 2.13.175-1212 +:Date: 23 February 2002 + +:: + + *** Updated f2py for the latest scipy_distutils. + *** A nasty bug with multi-dimensional Fortran arrays is fixed + (intent(out) arrays had wrong shapes). (Thanks to Eric for + pointing out this bug). + *** F2PY_REPORT_ATEXIT is disabled by default for __WIN32__. + + +:Release: 2.11.174-1161 +:Date: 14 February 2002 + +:: + + *** Updated f2py for the latest scipy_distutils. + *** Fixed raise error when f2py missed -m flag. + *** Script name `f2py' now depends on the name of python executable. + For example, `python2.2 setup.py install' will create a f2py + script with a name `f2py2.2'. + *** Introduced 'callprotoargument' statement so that proper prototypes + can be declared. This is crucial when wrapping C functions as it + will fix segmentation faults when these wrappers use non-pointer + arguments (thanks to R. Clint Whaley for explaining this to me). + Note that in f2py generated wrapper, the prototypes have + the following forms: + extern #rtype# #fortranname#(#callprotoargument#); + or + extern #rtype# F_FUNC(#fortranname#,#FORTRANNAME#)(#callprotoargument#); + *** Cosmetic fixes to F2PY_REPORT_ATEXIT feature. + + +:Release: 2.11.174-1146 +:Date: 3 February 2002 + +:: + + *** Reviewed reference counting in call-back mechanism. Fixed few bugs. + *** Enabled callstatement for complex functions. + *** Fixed bug with initializing capi_overwrite_<varname> + *** Introduced intent(overwrite) that is similar to intent(copy) but + has opposite effect. Renamed copy_<name>=1 to overwrite_<name>=0. + intent(overwrite) will make default overwrite_<name>=1. + *** Introduced intent(in|inout,out,out=<name>) attribute that renames + arguments name when returned. This renaming has effect only in + documentation strings. + *** Introduced 'callstatement' statement to pyf file syntax. With this + one can specify explicitly how wrapped function should be called + from the f2py generated module. WARNING: this is a dangerous feature + and should be used with care. It is introduced to provide a hack + to construct wrappers that may have very different signature + pattern from the wrapped function. Currently 'callstatement' can + be used only inside a subroutine or function block (it should be enough + though) and must be only in one continuous line. The syntax of the + statement is: callstatement <C-expression>; + + +:Release: 2.11.174 +:Date: 18 January 2002 + +:: + + *** Fixed memory-leak for PyFortranObject. + *** Introduced extra keyword argument copy_<varname> for intent(copy) + variables. It defaults to 1 and forces to make a copy for + intent(in) variables when passing on to wrapped functions (in case + they undesirably change the variable in-situ). + *** Introduced has_column_major_storage member function for all f2py + generated extension modules. It is equivalent to Python call + 'transpose(obj).iscontiguous()' but very efficient. + *** Introduced -DF2PY_REPORT_ATEXIT. If this is used when compiling, + a report is printed to stderr as python exits. The report includes + the following timings: + 1) time spent in all wrapped function calls; + 2) time spent in f2py generated interface around the wrapped + functions. This gives a hint whether one should worry + about storing data in proper order (C or Fortran). + 3) time spent in Python functions called by wrapped functions + through call-back interface. + 4) time spent in f2py generated call-back interface. + For now, -DF2PY_REPORT_ATEXIT is enabled by default. Use + -DF2PY_REPORT_ATEXIT_DISABLE to disable it (I am not sure if + Windows has needed tools, let me know). + Also, I appreciate if you could send me the output of 'F2PY + performance report' (with CPU and platform information) so that I + could optimize f2py generated interfaces for future releases. + *** Extension modules can be linked with dmalloc library. Use + -DDMALLOC when compiling. + *** Moved array_from_pyobj to fortranobject.c. + *** Usage of intent(inout) arguments is made more strict -- only + with proper type contiguous arrays are accepted. In general, + you should avoid using intent(inout) attribute as it makes + wrappers of C and Fortran functions asymmetric. I recommend using + intent(in,out) instead. + *** intent(..) has new keywords: copy,cache. + intent(copy,in) - forces a copy of an input argument; this + may be useful for cases where the wrapped function changes + the argument in situ and this may not be desired side effect. + Otherwise, it is safe to not use intent(copy) for the sake + of a better performance. + intent(cache,hide|optional) - just creates a junk of memory. + It does not care about proper storage order. Can be also + intent(in) but then the corresponding argument must be a + contiguous array with a proper elsize. + *** intent(c) can be used also for subroutine names so that + -DNO_APPEND_FORTRAN can be avoided for C functions. + + *** IMPORTANT BREAKING GOOD ... NEWS!!!: + + From now on you don't have to worry about the proper storage order + in multi-dimensional arrays that was earlier a real headache when + wrapping Fortran functions. Now f2py generated modules take care + of the proper conversations when needed. I have carefully designed + and optimized this interface to avoid any unnecessary memory usage + or copying of data. However, it is wise to use input arrays that + has proper storage order: for C arguments it is row-major and for + Fortran arguments it is column-major. But you don't need to worry + about that when developing your programs. The optimization of + initializing the program with proper data for possibly better + memory usage can be safely postponed until the program is working. + + This change also affects the signatures in .pyf files. If you have + created wrappers that take multi-dimensional arrays in arguments, + it is better to let f2py re-generate these files. Or you have to + manually do the following changes: reverse the axes indices in all + 'shape' macros. For example, if you have defined an array A(n,m) + and n=shape(A,1), m=shape(A,0) then you must change the last + statements to n=shape(A,0), m=shape(A,1). + + +:Release: 2.8.172 +:Date: 13 January 2002 + +:: + + *** Fixed -c process. Removed pyf_extensions function and pyf_file class. + *** Reorganized setup.py. It generates f2py or f2py.bat scripts + depending on the OS and the location of the python executable. + *** Started to use update_version from scipy_distutils that makes + f2py startup faster. As a side effect, the version number system + changed. + *** Introduced test-site/test_f2py2e.py script that runs all + tests. + *** Fixed global variables initialization problem in crackfortran + when run_main is called several times. + *** Added 'import Numeric' to C/API init<module> function. + *** Fixed f2py.bat in setup.py. + *** Switched over to scipy_distutils and dropped fortran_support. + *** On Windows create f2py.bat file. + *** Introduced -c option: read fortran or pyf files, construct extension + modules, build, and save them to current directory. + In one word: do-it-all-in-one-call. + *** Introduced pyf_extensions(sources,f2py_opts) function. It simplifies + the extension building process considerably. Only for internal use. + *** Converted tests to use scipy_distutils in order to improve portability: + a,b,c + *** f2py2e.run_main() returns a pyf_file class instance containing + information about f2py generated files. + *** Introduced `--build-dir <dirname>' command line option. + *** Fixed setup.py for bdist_rpm command. + *** Added --scipy-setup command line option. + *** Fixed crackfortran that did not recognized capitalized type + specification with --no-lower flag. + *** `-h stdout' writes signature to stdout. + *** Fixed incorrect message for check() with empty name list. + + +:Release: 2.4.366 +:Date: 17 December 2001 + +:: + + *** Added command line option --[no-]manifest. + *** `make test' should run on Windows, but the results are not truthful. + *** Reorganized f2py2e.py a bit. Introduced run_main(comline_list) function + that can be useful when running f2py from another Python module. + *** Removed command line options -f77,-fix,-f90 as the file format + is determined from the extension of the fortran file + or from its header (first line starting with `!%' and containing keywords + free, fix, or f77). The later overrides the former one. + *** Introduced command line options --[no-]makefile,--[no-]latex-doc. + Users must explicitly use --makefile,--latex-doc if Makefile-<modulename>, + <modulename>module.tex is desired. --setup is default. Use --no-setup + to disable setup_<modulename>.py generation. --overwrite-makefile + will set --makefile. + *** Added `f2py_rout_' to #capiname# in rules.py. + *** intent(...) statement with empty namelist forces intent(...) attribute for + all arguments. + *** Dropped DL_IMPORT and DL_EXPORT in fortranobject.h. + *** Added missing PyFortran_Type.ob_type initialization. + *** Added gcc-3.0 support. + *** Raising non-existing/broken Numeric as a FatalError exception. + *** Fixed Python 2.x specific += construct in fortran_support.py. + *** Fixed copy_ND_array for 1-rank arrays that used to call calloc(0,..) + and caused core dump with a non-gcc compiler (Thanks to Pierre Schnizer + for reporting this bug). + *** Fixed "warning: variable `..' might be clobbered by `longjmp' or `vfork'": + - Reorganized the structure of wrapper functions to get rid of + `goto capi_fail' statements that caused the above warning. + + +:Release: 2.3.343 +:Date: 12 December 2001 + +:: + + *** Issues with the Win32 support (thanks to Eric Jones and Tiffany Kamm): + - Using DL_EXPORT macro for init#modulename#. + - Changed PyObject_HEAD_INIT(&PyType_Type) to PyObject_HEAD_INIT(0). + - Initializing #name#_capi=NULL instead of Py_None in cb hooks. + *** Fixed some 'warning: function declaration isn't a prototype', mainly + in fortranobject.{c,h}. + *** Fixed 'warning: missing braces around initializer'. + *** Fixed reading a line containing only a label. + *** Fixed nonportable 'cp -fv' to shutil.copy in f2py2e.py. + *** Replaced PyEval_CallObject with PyObject_CallObject in cb_rules. + *** Replaced Py_DECREF with Py_XDECREF when freeing hidden arguments. + (Reason: Py_DECREF caused segfault when an error was raised) + *** Impl. support for `include "file"' (in addition to `include 'file'') + *** Fixed bugs (buildsetup.py missing in Makefile, in generated MANIFEST.in) + + +:Release: 2.3.327 +:Date: 4 December 2001 + +:: + + *** Sending out the third public release of f2py. + *** Support for Intel(R) Fortran Compiler (thanks to Patrick LeGresley). + *** Introduced `threadsafe' statement to pyf-files (or to be used with + the 'f2py' directive in fortran codes) to force + Py_BEGIN|END_ALLOW_THREADS block around the Fortran subroutine + calling statement in Python C/API. `threadsafe' statement has + an effect only inside a subroutine block. + *** Introduced `fortranname <name>' statement to be used only within + pyf-files. This is useful when the wrapper (Python C/API) function + has different name from the wrapped (Fortran) function. + *** Introduced `intent(c)' directive and statement. It is useful when + wrapping C functions. Use intent(c) for arguments that are + scalars (not pointers) or arrays (with row-ordering of elements). + + +:Release: 2.3.321 +:Date: 3 December 2001 + +:: + + *** f2py2e can be installed using distutils (run `python setup.py install'). + *** f2py builds setup_<modulename>.py. Use --[no-]setup to control this + feature. setup_<modulename>.py uses fortran_support module (from SciPy), + but for your convenience it is included also with f2py as an additional + package. Note that it has not as many compilers supported as with + using Makefile-<modulename>, but new compilers should be added to + fortran_support module, not to f2py2e package. + *** Fixed some compiler warnings about else statements. + diff --git a/numpy/f2py/docs/OLDNEWS.txt b/numpy/f2py/docs/OLDNEWS.txt new file mode 100644 index 000000000..b21215464 --- /dev/null +++ b/numpy/f2py/docs/OLDNEWS.txt @@ -0,0 +1,63 @@ + +.. topic:: Old F2PY NEWS + + March 30, 2004 + F2PY bug fix release (version 2.39.235-1693). Two new command line switches: + ``--compiler`` and ``--include_paths``. Support for allocatable string arrays. + Callback arguments may now be arbitrary callable objects. Win32 installers + for F2PY and Scipy_core are provided. + `Differences with the previous release (version 2.37.235-1660)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.98&r2=1.87&f=h + + + March 9, 2004 + F2PY bug fix release (version 2.39.235-1660). + `Differences with the previous release (version 2.37.235-1644)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.87&r2=1.83&f=h + + February 24, 2004 + Latest F2PY release (version 2.39.235-1644). + Support for scipy_distutils 0.2.2 and up (e.g. compiler flags can be + changed via f2py command line options). Implemented support for + character arrays and arrays of strings (e.g. ``character*(*) a(m,..)``). + *Important bug fixes regarding complex arguments, upgrading is + highly recommended*. Documentation updates. + `Differences with the previous release (version 2.37.233-1545)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.83&r2=1.58&f=h + + September 11, 2003 + Latest F2PY release (version 2.37.233-1545). + New statements: ``pymethoddef`` and ``usercode`` in interface blocks. + New function: ``as_column_major_storage``. + New CPP macro: ``F2PY_REPORT_ON_ARRAY_COPY``. + Bug fixes. + `Differences with the previous release (version 2.35.229-1505)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.58&r2=1.49&f=h + + August 2, 2003 + Latest F2PY release (version 2.35.229-1505). + `Differences with the previous release (version 2.32.225-1419)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.49&r2=1.28&f=h + + April 2, 2003 + Initial support for Numarray_ (thanks to Todd Miller). + + December 8, 2002 + Sixth public release of F2PY (version 2.32.225-1419). Comes with + revised `F2PY Users Guide`__, `new testing site`__, lots of fixes + and other improvements, see `HISTORY.txt`_ for details. + + __ usersguide/index.html + __ TESTING.txt_ + +.. References + ========== + +.. _HISTORY.txt: HISTORY.html +.. _Numarray: http://www.stsci.edu/resources/software_hardware/numarray +.. _TESTING.txt: TESTING.html
\ No newline at end of file diff --git a/numpy/f2py/docs/README.txt b/numpy/f2py/docs/README.txt new file mode 100644 index 000000000..fc7149645 --- /dev/null +++ b/numpy/f2py/docs/README.txt @@ -0,0 +1,457 @@ +.. -*- rest -*- + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + F2PY: Fortran to Python interface generator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Author: Pearu Peterson <pearu@cens.ioc.ee> +:License: LGPL_. +:Web-site: http://cens.ioc.ee/projects/f2py2e/ +:Discussions to: `f2py-users mailing list`_ +:Documentation: `User's Guide`__, FAQ__ +:Platforms: All +:Date: $Date: 2005/01/30 18:54:53 $ + +.. _f2py-users mailing list: http://cens.ioc.ee/mailman/listinfo/f2py-users/ +__ usersguide/index.html +__ FAQ.html + +------------------------------- + +.. topic:: NEWS!!! + + January 30, 2005 + + Latest F2PY release (version 2.45.241_1926). + New features: wrapping unsigned integers, support for ``.pyf.src`` template files, + callback arguments can now be CObjects, fortran objects, built-in functions. + Introduced ``intent(aux)`` attribute. Wrapped objects have ``_cpointer`` + attribute holding C pointer to wrapped functions or variables. + Many bug fixes and improvements, updated documentation. + `Differences with the previous release (version 2.43.239_1831)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.163&r2=1.137&f=h + + October 4, 2004 + F2PY bug fix release (version 2.43.239_1831). + Better support for 64-bit platforms. + Introduced ``--help-link`` and ``--link-<resource>`` options. + Bug fixes. + `Differences with the previous release (version 2.43.239_1806)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.137&r2=1.131&f=h + + September 25, 2004 + Latest F2PY release (version 2.43.239_1806). + Support for ``ENTRY`` statement. New attributes: + ``intent(inplace)``, ``intent(callback)``. Supports Numarray 1.1. + Introduced ``-*- fix -*-`` header content. Improved ``PARAMETER`` support. + Documentation updates. `Differences with the previous release + (version 2.39.235-1693)`__. + + __ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt.diff?r1=1.131&r2=1.98&f=h + + `History of NEWS`__ + + __ OLDNEWS.html + +------------------------------- + +.. Contents:: + +============== + Introduction +============== + +The purpose of the F2PY --*Fortran to Python interface generator*-- +project is to provide connection between Python_ and Fortran +languages. F2PY is a Python extension tool for creating Python C/API +modules from (handwritten or F2PY generated) signature files (or +directly from Fortran sources). The generated extension modules +facilitate: + +* Calling Fortran 77/90/95, Fortran 90/95 module, and C functions from + Python. + +* Accessing Fortran 77 ``COMMON`` blocks and Fortran 90/95 module + data (including allocatable arrays) from Python. + +* Calling Python functions from Fortran or C (call-backs). + +* Automatically handling the difference in the data storage order of + multi-dimensional Fortran and Numerical Python (i.e. C) arrays. + +In addition, F2PY can build the generated extension modules to shared +libraries with one command. F2PY uses the ``scipy_distutils`` module +from SciPy_ that supports number of major Fortran compilers. + +.. + (see `COMPILERS.txt`_ for more information). + +F2PY generated extension modules depend on NumPy_ package that +provides fast multi-dimensional array language facility to Python. + + +--------------- + Main features +--------------- + +Here follows a more detailed list of F2PY features: + +* F2PY scans real Fortran codes to produce the so-called signature + files (.pyf files). The signature files contain all the information + (function names, arguments and their types, etc.) that is needed to + construct Python bindings to Fortran (or C) functions. + + The syntax of signature files is borrowed from the + Fortran 90/95 language specification and has some F2PY specific + extensions. The signature files can be modified to dictate how + Fortran (or C) programs are called from Python: + + + F2PY solves dependencies between arguments (this is relevant for + the order of initializing variables in extension modules). + + + Arguments can be specified to be optional or hidden that + simplifies calling Fortran programs from Python considerably. + + + In principle, one can design any Python signature for a given + Fortran function, e.g. change the order arguments, introduce + auxiliary arguments, hide the arguments, process the arguments + before passing to Fortran, return arguments as output of F2PY + generated functions, etc. + +* F2PY automatically generates __doc__ strings (and optionally LaTeX + documentation) for extension modules. + +* F2PY generated functions accept arbitrary (but sensible) Python + objects as arguments. The F2PY interface automatically takes care of + type-casting and handling of non-contiguous arrays. + +* The following Fortran constructs are recognized by F2PY: + + + All basic Fortran types:: + + integer[ | *1 | *2 | *4 | *8 ], logical[ | *1 | *2 | *4 | *8 ] + integer*([ -1 | -2 | -4 | -8 ]) + character[ | *(*) | *1 | *2 | *3 | ... ] + real[ | *4 | *8 | *16 ], double precision + complex[ | *8 | *16 | *32 ] + + Negative ``integer`` kinds are used to wrap unsigned integers. + + + Multi-dimensional arrays of all basic types with the following + dimension specifications:: + + <dim> | <start>:<end> | * | : + + + Attributes and statements:: + + intent([ in | inout | out | hide | in,out | inout,out | c | + copy | cache | callback | inplace | aux ]) + dimension(<dimspec>) + common, parameter + allocatable + optional, required, external + depend([<names>]) + check([<C-booleanexpr>]) + note(<LaTeX text>) + usercode, callstatement, callprotoargument, threadsafe, fortranname + pymethoddef + entry + +* Because there are only little (and easily handleable) differences + between calling C and Fortran functions from F2PY generated + extension modules, then F2PY is also well suited for wrapping C + libraries to Python. + +* Practice has shown that F2PY generated interfaces (to C or Fortran + functions) are less error prone and even more efficient than + handwritten extension modules. The F2PY generated interfaces are + easy to maintain and any future optimization of F2PY generated + interfaces transparently apply to extension modules by just + regenerating them with the latest version of F2PY. + +* `F2PY Users Guide and Reference Manual`_ + + +=============== + Prerequisites +=============== + +F2PY requires the following software installed: + +* Python_ (versions 1.5.2 or later; 2.1 and up are recommended). + You must have python-dev package installed. +* NumPy_ (versions 13 or later; 20.x, 21.x, 22.x, 23.x are recommended) +* Numarray_ (version 0.9 and up), optional, partial support. +* Scipy_distutils (version 0.2.2 and up are recommended) from SciPy_ + project. Get it from Scipy CVS or download it below. + +Python 1.x users also need distutils_. + +Of course, to build extension modules, you'll need also working C +and/or Fortran compilers installed. + +========== + Download +========== + +You can download the sources for the latest F2PY and scipy_distutils +releases as: + +* `2.x`__/`F2PY-2-latest.tar.gz`__ +* `2.x`__/`scipy_distutils-latest.tar.gz`__ + +Windows users might be interested in Win32 installer for F2PY and +Scipy_distutils (these installers are built using Python 2.3): + +* `2.x`__/`F2PY-2-latest.win32.exe`__ +* `2.x`__/`scipy_distutils-latest.win32.exe`__ + +Older releases are also available in the directories +`rel-0.x`__, `rel-1.x`__, `rel-2.x`__, `rel-3.x`__, `rel-4.x`__, `rel-5.x`__, +if you need them. + +.. __: 2.x/ +.. __: 2.x/F2PY-2-latest.tar.gz +.. __: 2.x/ +.. __: 2.x/scipy_distutils-latest.tar.gz +.. __: 2.x/ +.. __: 2.x/F2PY-2-latest.win32.exe +.. __: 2.x/ +.. __: 2.x/scipy_distutils-latest.win32.exe +.. __: rel-0.x +.. __: rel-1.x +.. __: rel-2.x +.. __: rel-3.x +.. __: rel-4.x +.. __: rel-5.x + +Development version of F2PY from CVS is available as `f2py2e.tar.gz`__. + +__ http://cens.ioc.ee/cgi-bin/viewcvs.cgi/python/f2py2e/f2py2e.tar.gz?tarball=1 + +Debian Sid users can simply install ``python-f2py`` package. + +============== + Installation +============== + +Unpack the source file, change to directrory ``F2PY-?-???/`` and run +(you may need to become a root):: + + python setup.py install + +The F2PY installation installs a Python package ``f2py2e`` to your +Python ``site-packages`` directory and a script ``f2py`` to your +Python executable path. + +See also Installation__ section in `F2PY FAQ`_. + +.. __: FAQ.html#installation + +Similarly, to install ``scipy_distutils``, unpack its tar-ball and run:: + + python setup.py install + +======= + Usage +======= + +To check if F2PY is installed correctly, run +:: + + f2py + +without any arguments. This should print out the usage information of +the ``f2py`` program. + +Next, try out the following three steps: + +1) Create a Fortran file `hello.f`__ that contains:: + + C File hello.f + subroutine foo (a) + integer a + print*, "Hello from Fortran!" + print*, "a=",a + end + +__ hello.f + +2) Run + + :: + + f2py -c -m hello hello.f + + This will build an extension module ``hello.so`` (or ``hello.sl``, + or ``hello.pyd``, etc. depending on your platform) into the current + directory. + +3) Now in Python try:: + + >>> import hello + >>> print hello.__doc__ + >>> print hello.foo.__doc__ + >>> hello.foo(4) + Hello from Fortran! + a= 4 + >>> + +If the above works, then you can try out more thorough +`F2PY unit tests`__ and read the `F2PY Users Guide and Reference Manual`_. + +__ FAQ.html#q-how-to-test-if-f2py-is-working-correctly + +=============== + Documentation +=============== + +The documentation of the F2PY project is collected in ``f2py2e/docs/`` +directory. It contains the following documents: + +`README.txt`_ (in CVS__) + The first thing to read about F2PY -- this document. + +__ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/README.txt?rev=HEAD&content-type=text/x-cvsweb-markup + +`usersguide/index.txt`_, `usersguide/f2py_usersguide.pdf`_ + F2PY Users Guide and Reference Manual. Contains lots of examples. + +`FAQ.txt`_ (in CVS__) + F2PY Frequently Asked Questions. + +__ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/FAQ.txt?rev=HEAD&content-type=text/x-cvsweb-markup + +`TESTING.txt`_ (in CVS__) + About F2PY testing site. What tests are available and how to run them. + +__ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/TESTING.txt?rev=HEAD&content-type=text/x-cvsweb-markup + +`HISTORY.txt`_ (in CVS__) + A list of latest changes in F2PY. This is the most up-to-date + document on F2PY. + +__ http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt?rev=HEAD&content-type=text/x-cvsweb-markup + +`THANKS.txt`_ + Acknowledgments. + +.. + `COMPILERS.txt`_ + Compiler and platform specific notes. + +=============== + Mailing list +=============== + +A mailing list f2py-users@cens.ioc.ee is open for F2PY releated +discussion/questions/etc. + +* `Subscribe..`__ +* `Archives..`__ + +__ http://cens.ioc.ee/mailman/listinfo/f2py-users +__ http://cens.ioc.ee/pipermail/f2py-users + + +===== + CVS +===== + +F2PY is being developed under CVS_. The CVS version of F2PY can be +obtained as follows: + +1) First you need to login (the password is ``guest``):: + + cvs -d :pserver:anonymous@cens.ioc.ee:/home/cvs login + +2) and then do the checkout:: + + cvs -z6 -d :pserver:anonymous@cens.ioc.ee:/home/cvs checkout f2py2e + +3) You can update your local F2PY tree ``f2py2e/`` by executing:: + + cvs -z6 update -P -d + +You can browse the `F2PY CVS`_ repository. + +=============== + Contributions +=============== + +* `A short introduction to F2PY`__ by Pierre Schnizer. + +* `F2PY notes`__ by Fernando Perez. + +* `Debian packages of F2PY`__ by José Fonseca. [OBSOLETE, Debian Sid + ships python-f2py package] + +__ http://fubphpc.tu-graz.ac.at/~pierre/f2py_tutorial.tar.gz +__ http://cens.ioc.ee/pipermail/f2py-users/2003-April/000472.html +__ http://jrfonseca.dyndns.org/debian/ + + +=============== + Related sites +=============== + +* `Numerical Python`_ -- adds a fast array facility to the Python language. +* Pyfort_ -- A Python-Fortran connection tool. +* SciPy_ -- An open source library of scientific tools for Python. +* `Scientific Python`_ -- A collection of Python modules that are + useful for scientific computing. +* `The Fortran Company`_ -- A place to find products, services, and general + information related to the Fortran programming language. +* `American National Standard Programming Language FORTRAN ANSI(R) X3.9-1978`__ +* `J3`_ -- The US Fortran standards committee. +* SWIG_ -- A software development tool that connects programs written + in C and C++ with a variety of high-level programming languages. +* `Mathtools.net`_ -- A technical computing portal for all scientific + and engineering needs. + +.. __: http://www.fortran.com/fortran/F77_std/rjcnf.html + +.. References + ========== + + +.. _F2PY Users Guide and Reference Manual: usersguide/index.html +.. _usersguide/index.txt: usersguide/index.html +.. _usersguide/f2py_usersguide.pdf: usersguide/f2py_usersguide.pdf +.. _README.txt: README.html +.. _COMPILERS.txt: COMPILERS.html +.. _F2PY FAQ: +.. _FAQ.txt: FAQ.html +.. _HISTORY.txt: HISTORY.html +.. _HISTORY.txt from CVS: http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/docs/HISTORY.txt?rev=HEAD&content-type=text/x-cvsweb-markup +.. _THANKS.txt: THANKS.html +.. _TESTING.txt: TESTING.html +.. _F2PY CVS2: http://cens.ioc.ee/cgi-bin/cvsweb/python/f2py2e/ +.. _F2PY CVS: http://cens.ioc.ee/cgi-bin/viewcvs.cgi/python/f2py2e/ + +.. _CVS: http://www.cvshome.org/ +.. _Python: http://www.python.org/ +.. _SciPy: http://www.scipy.org/ +.. _NumPy: http://www.numpy.org/ +.. _Numarray: http://www.stsci.edu/resources/software_hardware/numarray +.. _docutils: http://docutils.sourceforge.net/ +.. _distutils: http://www.python.org/sigs/distutils-sig/ +.. _LGPL: http://www.fsf.org/copyleft/lesser.html +.. _Numerical Python: http://www.numpy.org/ +.. _Pyfort: http://pyfortran.sourceforge.net/ +.. _Scientific Python: + http://starship.python.net/crew/hinsen/scientific.html +.. _The Fortran Company: http://www.fortran.com/fortran/ +.. _J3: http://www.j3-fortran.org/ +.. _Mathtools.net: http://www.mathtools.net/ +.. _SWIG: http://www.swig.org/ + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: diff --git a/numpy/f2py/docs/TESTING.txt b/numpy/f2py/docs/TESTING.txt new file mode 100644 index 000000000..feae18dc6 --- /dev/null +++ b/numpy/f2py/docs/TESTING.txt @@ -0,0 +1,108 @@ + +======================================================= + F2PY unit testing site +======================================================= + +.. Contents:: + +Tests +----- + +* To run all F2PY unit tests in one command:: + + cd tests + python run_all.py [<options>] + + For example:: + + localhost:~/src_cvs/f2py2e/tests$ python2.2 run_all.py 100 --quiet + ********************************************** + Running '/usr/bin/python2.2 f77/return_integer.py 100 --quiet' + run 1000 tests in 1.87 seconds + initial virtual memory size: 3952640 bytes + current virtual memory size: 3952640 bytes + ok + ********************************************** + Running '/usr/bin/python2.2 f77/return_logical.py 100 --quiet' + run 1000 tests in 1.47 seconds + initial virtual memory size: 3952640 bytes + current virtual memory size: 3952640 bytes + ok + ... + + If some tests fail, try to run the failing tests separately (without + the ``--quiet`` option) as described below to get more information + about the failure. + +* Test intent(in), intent(out) scalar arguments, + scalars returned by F77 functions + and F90 module functions:: + + tests/f77/return_integer.py + tests/f77/return_real.py + tests/f77/return_logical.py + tests/f77/return_complex.py + tests/f77/return_character.py + tests/f90/return_integer.py + tests/f90/return_real.py + tests/f90/return_logical.py + tests/f90/return_complex.py + tests/f90/return_character.py + + Change to tests/ directory and run:: + + python f77/return_<type>.py [<options>] + python f90/return_<type>.py [<options>] + + where ``<type>`` is integer, real, logical, complex, or character. + Test scripts options are described below. + + A test is considered succesful if the last printed line is "ok". + + If you get import errors like:: + + ImportError: No module named f77_ext_return_integer + + but ``f77_ext_return_integer.so`` exists in the current directory then + it means that the current directory is not included in to `sys.path` + in your Python installation. As a fix, prepend ``.`` to ``PYTHONPATH`` + environment variable and rerun the tests. For example:: + + PYTHONPATH=. python f77/return_integer.py + +* Test mixing Fortran 77, Fortran 90 fixed and free format codes:: + + tests/mixed/run.py + +* Test basic callback hooks:: + + tests/f77/callback.py + +Options +------- + +You may want to use the following options when running the test +scripts: + +``<integer>`` + Run tests ``<integer>`` times. Useful for detecting memory leaks. Under + Linux tests scripts output virtual memory size state of the process + before and after calling the wrapped functions. + +``--quiet`` + Suppress all messages. On success only "ok" should be displayed. + +``--fcompiler=<Gnu|Intel|...>`` + Use:: + + f2py -c --help-fcompiler + + to find out what compilers are available (or more precisely, which + ones are recognized by ``scipy_distutils``). + +Reporting failures +------------------ + +XXX: (1) make sure that failures are due to f2py and (2) send full +stdout/stderr messages to me. Also add compiler,python,platform +information. diff --git a/numpy/f2py/docs/THANKS.txt b/numpy/f2py/docs/THANKS.txt new file mode 100644 index 000000000..cbaa083fc --- /dev/null +++ b/numpy/f2py/docs/THANKS.txt @@ -0,0 +1,63 @@ + +================= + Acknowledgments +================= + +F2PY__ is a LGPL'd Python package and command line tool developed and +maintained by Pearu Peterson (me__). + +.. __: http://cens.ioc.ee/projects/f2py2e/ +.. __: http://cens.ioc.ee/~pearu/ + +Many people have contributed to the F2PY project in terms of interest, +encouragement, suggestions, criticism, bug reports, code +contributions, and keeping me busy with developing F2PY. For all that +I thank + + James Amundson, John Barnard, David Beazley, Frank Bertoldi, Roman + Bertle, James Boyle, Moritz Braun, Rolv Erlend Bredesen, John + Chaffer, Fred Clare, Adam Collard, Ben Cornett, Jose L Gomez Dans, + Jaime D. Perea Duarte, Paul F Dubois, Thilo Ernst, Bonilla Fabian, + Martin Gelfand, Eduardo A. Gonzalez, Siegfried Gonzi, Bernhard + Gschaider, Charles Doutriaux, Jeff Hagelberg, Janko Hauser, Thomas + Hauser, Heiko Henkelmann, William Henney, Yueqiang Huang, Asim + Hussain, Berthold Höllmann, Vladimir Janku, Henk Jansen, Curtis + Jensen, Eric Jones, Tiffany Kamm, Andrey Khavryuchenko, Greg + Kochanski, Jochen Küpper, Simon Lacoste-Julien, Tim Lahey, Hans + Petter Langtangen, Jeff Layton, Matthew Lewis, Patrick LeGresley, + Joaquim R R A Martins, Paul Magwene Lionel Maziere, Craig McNeile, + Todd Miller, David C. Morrill, Dirk Muders, Kevin Mueller, Andrew + Mullhaupt, Vijayendra Munikoti, Travis Oliphant, Kevin O'Mara, Arno + Paehler, Fernando Perez, Didrik Pinte, Todd Alan Pitts, Prabhu + Ramachandran, Brad Reisfeld, Steve M. Robbins, Theresa Robinson, + Pedro Rodrigues, Les Schaffer, Christoph Scheurer, Herb Schilling, + Pierre Schnizer, Kevin Smith, Paulo Teotonio Sobrinho, José Rui + Faustino de Sousa, Andrew Swan, Dustin Tang, Charlie Taylor, Paul le + Texier, Michael Tiller, Semen Trygubenko, Ravi C Venkatesan, Peter + Verveer, Nils Wagner, R. Clint Whaley, Erik Wilsher, Martin + Wiechert, Gilles Zerah, SungPil Yoon. + +(This list may not be complete. Please forgive me if I have left you +out and let me know, I'll add your name.) + +Special thanks are due to ... + +Eric Jones - he and Travis O. are responsible for starting the +scipy_distutils project that allowed to move most of the platform and +compiler specific codes out from F2PY. This simplified maintaining the +F2PY project considerably. + +Joaquim R R A Martins - he made possible for me to test F2PY on IRIX64 +platform. He also presented our paper about F2PY in the 9th Python +Conference that I planned to attend but had to cancel in very last +minutes. + +Travis Oliphant - his knowledge and experience on Numerical Python +C/API has been invaluable in early development of the F2PY program. +His major contributions are call-back mechanism and copying N-D arrays +of arbitrary types. + +Todd Miller - he is responsible for Numarray support in F2PY. + +Thanks! + Pearu diff --git a/numpy/f2py/docs/default.css b/numpy/f2py/docs/default.css new file mode 100644 index 000000000..9289e2826 --- /dev/null +++ b/numpy/f2py/docs/default.css @@ -0,0 +1,180 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:date: $Date: 2002/08/01 20:52:44 $ +:version: $Revision: 1.1 $ +:copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. +*/ + +body { + background: #FFFFFF ; + color: #000000 +} + +a.footnote-reference { + font-size: smaller ; + vertical-align: super } + +a.target { + color: blue } + +a.toc-backref { + text-decoration: none ; + color: black } + +dd { + margin-bottom: 0.5em } + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.attention, div.caution, div.danger, div.error, div.hint, +div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +div.hint p.admonition-title, div.important p.admonition-title, +div.note p.admonition-title, div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + font-size: smaller } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr { + width: 75% } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.first { + margin-top: 0 } + +p.label { + white-space: nowrap } + +p.topic-title { + font-weight: bold } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.field-argument { + font-style: italic } + +span.interpreted { + font-family: sans-serif } + +span.option-argument { + font-style: italic } + +span.problematic { + color: red } + +table { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.citation { + border-left: solid thin gray ; + padding-left: 0.5ex } + +table.docinfo { + margin: 2em 4em } + +table.footnote { + border-left: solid thin black ; + padding-left: 0.5ex } + +td, th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: baseline } + +td.docinfo-name { + font-weight: bold ; + text-align: right } + +td.field-name { + font-weight: bold } diff --git a/numpy/f2py/docs/docutils.conf b/numpy/f2py/docs/docutils.conf new file mode 100644 index 000000000..4e5a8425b --- /dev/null +++ b/numpy/f2py/docs/docutils.conf @@ -0,0 +1,16 @@ +[general] + +# These entries affect all processing: +#source-link: 1 +datestamp: %Y-%m-%d %H:%M UTC +generator: 1 + +# These entries affect HTML output: +#stylesheet-path: pearu_style.css +output-encoding: latin-1 + +# These entries affect reStructuredText-style PEPs: +#pep-template: pep-html-template +#pep-stylesheet-path: stylesheets/pep.css +#python-home: http://www.python.org +#no-random: 1 diff --git a/numpy/f2py/docs/hello.f b/numpy/f2py/docs/hello.f new file mode 100644 index 000000000..3e0dc6d21 --- /dev/null +++ b/numpy/f2py/docs/hello.f @@ -0,0 +1,7 @@ +C File hello.f + subroutine foo (a) + integer a + print*, "Hello from Fortran!" + print*, "a=",a + end + diff --git a/numpy/f2py/docs/pyforttest.pyf b/numpy/f2py/docs/pyforttest.pyf new file mode 100644 index 000000000..79a9ae205 --- /dev/null +++ b/numpy/f2py/docs/pyforttest.pyf @@ -0,0 +1,5 @@ +subroutine foo(a,m,n) +integer m = size(a,1) +integer n = size(a,2) +real, intent(inout) :: a(m,n) +end subroutine foo diff --git a/numpy/f2py/docs/pytest.py b/numpy/f2py/docs/pytest.py new file mode 100644 index 000000000..abd3487df --- /dev/null +++ b/numpy/f2py/docs/pytest.py @@ -0,0 +1,10 @@ +#File: pytest.py +import Numeric +def foo(a): + a = Numeric.array(a) + m,n = a.shape + for i in range(m): + for j in range(n): + a[i,j] = a[i,j] + 10*(i+1) + (j+1) + return a +#eof diff --git a/numpy/f2py/docs/simple.f b/numpy/f2py/docs/simple.f new file mode 100644 index 000000000..ba468a509 --- /dev/null +++ b/numpy/f2py/docs/simple.f @@ -0,0 +1,13 @@ +cFile: simple.f + subroutine foo(a,m,n) + integer m,n,i,j + real a(m,n) +cf2py intent(in,out) a +cf2py intent(hide) m,n + do i=1,m + do j=1,n + a(i,j) = a(i,j) + 10*i+j + enddo + enddo + end +cEOF diff --git a/numpy/f2py/docs/simple_session.dat b/numpy/f2py/docs/simple_session.dat new file mode 100644 index 000000000..10d9dc962 --- /dev/null +++ b/numpy/f2py/docs/simple_session.dat @@ -0,0 +1,51 @@ +>>> import pytest +>>> import f2pytest +>>> import pyforttest +>>> print f2pytest.foo.__doc__ +foo - Function signature: + a = foo(a) +Required arguments: + a : input rank-2 array('f') with bounds (m,n) +Return objects: + a : rank-2 array('f') with bounds (m,n) + +>>> print pyforttest.foo.__doc__ +foo(a) + +>>> pytest.foo([[1,2],[3,4]]) +array([[12, 14], + [24, 26]]) +>>> f2pytest.foo([[1,2],[3,4]]) # F2PY can handle arbitrary input sequences +array([[ 12., 14.], + [ 24., 26.]],'f') +>>> pyforttest.foo([[1,2],[3,4]]) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +pyforttest.error: foo, argument A: Argument intent(inout) must be an array. + +>>> import Numeric +>>> a=Numeric.array([[1,2],[3,4]],'f') +>>> f2pytest.foo(a) +array([[ 12., 14.], + [ 24., 26.]],'f') +>>> a # F2PY makes a copy when input array is not Fortran contiguous +array([[ 1., 2.], + [ 3., 4.]],'f') +>>> a=Numeric.transpose(Numeric.array([[1,3],[2,4]],'f')) +>>> a +array([[ 1., 2.], + [ 3., 4.]],'f') +>>> f2pytest.foo(a) +array([[ 12., 14.], + [ 24., 26.]],'f') +>>> a # F2PY passes Fortran contiguous input array directly to Fortran +array([[ 12., 14.], + [ 24., 26.]],'f') +# See intent(copy), intent(overwrite), intent(inplace), intent(inout) +# attributes documentation to enhance the above behavior. + +>>> a=Numeric.array([[1,2],[3,4]],'f') +>>> pyforttest.foo(a) +>>> a # Huh? Pyfort 8.5 gives wrong results.. +array([[ 12., 23.], + [ 15., 26.]],'f') diff --git a/numpy/f2py/docs/usersguide/allocarr.f90 b/numpy/f2py/docs/usersguide/allocarr.f90 new file mode 100644 index 000000000..e0d6c2ec8 --- /dev/null +++ b/numpy/f2py/docs/usersguide/allocarr.f90 @@ -0,0 +1,16 @@ +module mod + real, allocatable, dimension(:,:) :: b +contains + subroutine foo + integer k + if (allocated(b)) then + print*, "b=[" + do k = 1,size(b,1) + print*, b(k,1:size(b,2)) + enddo + print*, "]" + else + print*, "b is not allocated" + endif + end subroutine foo +end module mod diff --git a/numpy/f2py/docs/usersguide/allocarr_session.dat b/numpy/f2py/docs/usersguide/allocarr_session.dat new file mode 100644 index 000000000..fc91959b7 --- /dev/null +++ b/numpy/f2py/docs/usersguide/allocarr_session.dat @@ -0,0 +1,27 @@ +>>> import allocarr +>>> print allocarr.mod.__doc__ +b - 'f'-array(-1,-1), not allocated +foo - Function signature: + foo() + +>>> allocarr.mod.foo() + b is not allocated +>>> allocarr.mod.b = [[1,2,3],[4,5,6]] # allocate/initialize b +>>> allocarr.mod.foo() + b=[ + 1.000000 2.000000 3.000000 + 4.000000 5.000000 6.000000 + ] +>>> allocarr.mod.b # b is Fortran-contiguous +array([[ 1., 2., 3.], + [ 4., 5., 6.]],'f') +>>> allocarr.mod.b = [[1,2,3],[4,5,6],[7,8,9]] # reallocate/initialize b +>>> allocarr.mod.foo() + b=[ + 1.000000 2.000000 3.000000 + 4.000000 5.000000 6.000000 + 7.000000 8.000000 9.000000 + ] +>>> allocarr.mod.b = None # deallocate array +>>> allocarr.mod.foo() + b is not allocated diff --git a/numpy/f2py/docs/usersguide/array.f b/numpy/f2py/docs/usersguide/array.f new file mode 100644 index 000000000..ef20c9c20 --- /dev/null +++ b/numpy/f2py/docs/usersguide/array.f @@ -0,0 +1,17 @@ +C FILE: ARRAY.F + SUBROUTINE FOO(A,N,M) +C +C INCREMENT THE FIRST ROW AND DECREMENT THE FIRST COLUMN OF A +C + INTEGER N,M,I,J + REAL*8 A(N,M) +Cf2py intent(in,out,copy) a +Cf2py integer intent(hide),depend(a) :: n=shape(a,0), m=shape(a,1) + DO J=1,M + A(1,J) = A(1,J) + 1D0 + ENDDO + DO I=1,N + A(I,1) = A(I,1) - 1D0 + ENDDO + END +C END OF FILE ARRAY.F diff --git a/numpy/f2py/docs/usersguide/array_session.dat b/numpy/f2py/docs/usersguide/array_session.dat new file mode 100644 index 000000000..f64933482 --- /dev/null +++ b/numpy/f2py/docs/usersguide/array_session.dat @@ -0,0 +1,65 @@ +>>> import arr +>>> from Numeric import array +>>> print arr.foo.__doc__ +foo - Function signature: + a = foo(a,[overwrite_a]) +Required arguments: + a : input rank-2 array('d') with bounds (n,m) +Optional arguments: + overwrite_a := 0 input int +Return objects: + a : rank-2 array('d') with bounds (n,m) + +>>> a=arr.foo([[1,2,3], +... [4,5,6]]) +copied an array using PyArray_CopyFromObject: size=6, elsize=8 +>>> print a +[[ 1. 3. 4.] + [ 3. 5. 6.]] +>>> a.iscontiguous(), arr.has_column_major_storage(a) +(0, 1) +>>> b=arr.foo(a) # even if a is proper-contiguous +... # and has proper type, a copy is made +... # forced by intent(copy) attribute +... # to preserve its original contents +... +copied an array using copy_ND_array: size=6, elsize=8 +>>> print a +[[ 1. 3. 4.] + [ 3. 5. 6.]] +>>> print b +[[ 1. 4. 5.] + [ 2. 5. 6.]] +>>> b=arr.foo(a,overwrite_a=1) # a is passed directly to Fortran +... # routine and its contents is discarded +... +>>> print a +[[ 1. 4. 5.] + [ 2. 5. 6.]] +>>> print b +[[ 1. 4. 5.] + [ 2. 5. 6.]] +>>> a is b # a and b are acctually the same objects +1 +>>> print arr.foo([1,2,3]) # different rank arrays are allowed +copied an array using PyArray_CopyFromObject: size=3, elsize=8 +[ 1. 1. 2.] +>>> print arr.foo([[[1],[2],[3]]]) +copied an array using PyArray_CopyFromObject: size=3, elsize=8 +[ [[ 1.] + [ 3.] + [ 4.]]] +>>> +>>> # Creating arrays with column major data storage order: +... +>>> s = arr.as_column_major_storage(array([[1,2,3],[4,5,6]])) +copied an array using copy_ND_array: size=6, elsize=4 +>>> arr.has_column_major_storage(s) +1 +>>> print s +[[1 2 3] + [4 5 6]] +>>> s2 = arr.as_column_major_storage(s) +>>> s2 is s # an array with column major storage order + # is returned immediately +1
\ No newline at end of file diff --git a/numpy/f2py/docs/usersguide/calculate.f b/numpy/f2py/docs/usersguide/calculate.f new file mode 100644 index 000000000..1cda1c8dd --- /dev/null +++ b/numpy/f2py/docs/usersguide/calculate.f @@ -0,0 +1,14 @@ + subroutine calculate(x,n) +cf2py intent(callback) func + external func +c The following lines define the signature of func for F2PY: +cf2py real*8 y +cf2py y = func(y) +c +cf2py intent(in,out,copy) x + integer n,i + real*8 x(n) + do i=1,n + x(i) = func(x(i)) + end do + end diff --git a/numpy/f2py/docs/usersguide/calculate_session.dat b/numpy/f2py/docs/usersguide/calculate_session.dat new file mode 100644 index 000000000..2fe64f522 --- /dev/null +++ b/numpy/f2py/docs/usersguide/calculate_session.dat @@ -0,0 +1,6 @@ +>>> import foo +>>> foo.calculate(range(5), lambda x: x*x) +array([ 0., 1., 4., 9., 16.]) +>>> import math +>>> foo.calculate(range(5), math.exp) +array([ 1. , 2.71828175, 7.38905621, 20.08553696, 54.59814835]) diff --git a/numpy/f2py/docs/usersguide/callback.f b/numpy/f2py/docs/usersguide/callback.f new file mode 100644 index 000000000..6e9bfb920 --- /dev/null +++ b/numpy/f2py/docs/usersguide/callback.f @@ -0,0 +1,12 @@ +C FILE: CALLBACK.F + SUBROUTINE FOO(FUN,R) + EXTERNAL FUN + INTEGER I + REAL*8 R +Cf2py intent(out) r + R = 0D0 + DO I=-5,5 + R = R + FUN(I) + ENDDO + END +C END OF FILE CALLBACK.F diff --git a/numpy/f2py/docs/usersguide/callback2.pyf b/numpy/f2py/docs/usersguide/callback2.pyf new file mode 100644 index 000000000..3d77eed24 --- /dev/null +++ b/numpy/f2py/docs/usersguide/callback2.pyf @@ -0,0 +1,19 @@ +! -*- f90 -*- +python module __user__routines + interface + function fun(i) result (r) + integer :: i + real*8 :: r + end function fun + end interface +end python module __user__routines + +python module callback2 + interface + subroutine foo(f,r) + use __user__routines, f=>fun + external f + real*8 intent(out) :: r + end subroutine foo + end interface +end python module callback2 diff --git a/numpy/f2py/docs/usersguide/callback_session.dat b/numpy/f2py/docs/usersguide/callback_session.dat new file mode 100644 index 000000000..cd2f26084 --- /dev/null +++ b/numpy/f2py/docs/usersguide/callback_session.dat @@ -0,0 +1,23 @@ +>>> import callback +>>> print callback.foo.__doc__ +foo - Function signature: + r = foo(fun,[fun_extra_args]) +Required arguments: + fun : call-back function +Optional arguments: + fun_extra_args := () input tuple +Return objects: + r : float +Call-back functions: + def fun(i): return r + Required arguments: + i : input int + Return objects: + r : float + +>>> def f(i): return i*i +... +>>> print callback.foo(f) +110.0 +>>> print callback.foo(lambda i:1) +11.0 diff --git a/numpy/f2py/docs/usersguide/common.f b/numpy/f2py/docs/usersguide/common.f new file mode 100644 index 000000000..b098ab20c --- /dev/null +++ b/numpy/f2py/docs/usersguide/common.f @@ -0,0 +1,13 @@ +C FILE: COMMON.F + SUBROUTINE FOO + INTEGER I,X + REAL A + COMMON /DATA/ I,X(4),A(2,3) + PRINT*, "I=",I + PRINT*, "X=[",X,"]" + PRINT*, "A=[" + PRINT*, "[",A(1,1),",",A(1,2),",",A(1,3),"]" + PRINT*, "[",A(2,1),",",A(2,2),",",A(2,3),"]" + PRINT*, "]" + END +C END OF COMMON.F diff --git a/numpy/f2py/docs/usersguide/common_session.dat b/numpy/f2py/docs/usersguide/common_session.dat new file mode 100644 index 000000000..846fdaa07 --- /dev/null +++ b/numpy/f2py/docs/usersguide/common_session.dat @@ -0,0 +1,27 @@ +>>> import common +>>> print common.data.__doc__ +i - 'i'-scalar +x - 'i'-array(4) +a - 'f'-array(2,3) + +>>> common.data.i = 5 +>>> common.data.x[1] = 2 +>>> common.data.a = [[1,2,3],[4,5,6]] +>>> common.foo() + I= 5 + X=[ 0 2 0 0] + A=[ + [ 1., 2., 3.] + [ 4., 5., 6.] + ] +>>> common.data.a[1] = 45 +>>> common.foo() + I= 5 + X=[ 0 2 0 0] + A=[ + [ 1., 2., 3.] + [ 45., 45., 45.] + ] +>>> common.data.a # a is Fortran-contiguous +array([[ 1., 2., 3.], + [ 45., 45., 45.]],'f') diff --git a/numpy/f2py/docs/usersguide/compile_session.dat b/numpy/f2py/docs/usersguide/compile_session.dat new file mode 100644 index 000000000..0d8408198 --- /dev/null +++ b/numpy/f2py/docs/usersguide/compile_session.dat @@ -0,0 +1,11 @@ +>>> import f2py2e +>>> fsource = ''' +... subroutine foo +... print*, "Hello world!" +... end +... ''' +>>> f2py2e.compile(fsource,modulename='hello',verbose=0) +0 +>>> import hello +>>> hello.foo() + Hello world! diff --git a/numpy/f2py/docs/usersguide/default.css b/numpy/f2py/docs/usersguide/default.css new file mode 100644 index 000000000..bb7226161 --- /dev/null +++ b/numpy/f2py/docs/usersguide/default.css @@ -0,0 +1,180 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:date: $Date: 2002/12/07 23:59:33 $ +:version: $Revision: 1.2 $ +:copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. +*/ + +body { + background: #FFFFFF ; + color: #000000 +} + +a.footnote-reference { + font-size: smaller ; + vertical-align: super } + +a.target { + color: blue } + +a.toc-backref { + text-decoration: none ; + color: black } + +dd { + margin-bottom: 0.5em } + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.attention, div.caution, div.danger, div.error, div.hint, +div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +div.hint p.admonition-title, div.important p.admonition-title, +div.note p.admonition-title, div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + font-size: smaller } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr { + width: 75% } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.first { + margin-top: 0 } + +p.label { + white-space: nowrap } + +p.topic-title { + font-weight: bold } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #ee9e9e } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.field-argument { + font-style: italic } + +span.interpreted { + font-family: sans-serif } + +span.option-argument { + font-style: italic } + +span.problematic { + color: red } + +table { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.citation { + border-left: solid thin gray ; + padding-left: 0.5ex } + +table.docinfo { + margin: 2em 4em } + +table.footnote { + border-left: solid thin black ; + padding-left: 0.5ex } + +td, th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: baseline } + +td.docinfo-name { + font-weight: bold ; + text-align: right } + +td.field-name { + font-weight: bold } diff --git a/numpy/f2py/docs/usersguide/docutils.conf b/numpy/f2py/docs/usersguide/docutils.conf new file mode 100644 index 000000000..b772fd137 --- /dev/null +++ b/numpy/f2py/docs/usersguide/docutils.conf @@ -0,0 +1,16 @@ +[general] + +# These entries affect all processing: +#source-link: 1 +datestamp: %Y-%m-%d %H:%M UTC +generator: 1 + +# These entries affect HTML output: +#stylesheet-path: f2py_style.css +output-encoding: latin-1 + +# These entries affect reStructuredText-style PEPs: +#pep-template: pep-html-template +#pep-stylesheet-path: stylesheets/pep.css +#python-home: http://www.python.org +#no-random: 1 diff --git a/numpy/f2py/docs/usersguide/extcallback.f b/numpy/f2py/docs/usersguide/extcallback.f new file mode 100644 index 000000000..9a800628e --- /dev/null +++ b/numpy/f2py/docs/usersguide/extcallback.f @@ -0,0 +1,14 @@ + subroutine f1() + print *, "in f1, calling f2 twice.." + call f2() + call f2() + return + end + + subroutine f2() +cf2py intent(callback, hide) fpy + external fpy + print *, "in f2, calling f2py.." + call fpy() + return + end diff --git a/numpy/f2py/docs/usersguide/extcallback_session.dat b/numpy/f2py/docs/usersguide/extcallback_session.dat new file mode 100644 index 000000000..c22935ea0 --- /dev/null +++ b/numpy/f2py/docs/usersguide/extcallback_session.dat @@ -0,0 +1,19 @@ +>>> import pfromf +>>> pfromf.f2() +Traceback (most recent call last): + File "<stdin>", line 1, in ? +pfromf.error: Callback fpy not defined (as an argument or module pfromf attribute). + +>>> def f(): print "python f" +... +>>> pfromf.fpy = f +>>> pfromf.f2() + in f2, calling f2py.. +python f +>>> pfromf.f1() + in f1, calling f2 twice.. + in f2, calling f2py.. +python f + in f2, calling f2py.. +python f +>>>
\ No newline at end of file diff --git a/numpy/f2py/docs/usersguide/fib1.f b/numpy/f2py/docs/usersguide/fib1.f new file mode 100644 index 000000000..cfbb1eea0 --- /dev/null +++ b/numpy/f2py/docs/usersguide/fib1.f @@ -0,0 +1,18 @@ +C FILE: FIB1.F + SUBROUTINE FIB(A,N) +C +C CALCULATE FIRST N FIBONACCI NUMBERS +C + INTEGER N + REAL*8 A(N) + DO I=1,N + IF (I.EQ.1) THEN + A(I) = 0.0D0 + ELSEIF (I.EQ.2) THEN + A(I) = 1.0D0 + ELSE + A(I) = A(I-1) + A(I-2) + ENDIF + ENDDO + END +C END FILE FIB1.F diff --git a/numpy/f2py/docs/usersguide/fib1.pyf b/numpy/f2py/docs/usersguide/fib1.pyf new file mode 100644 index 000000000..3d6cc0a54 --- /dev/null +++ b/numpy/f2py/docs/usersguide/fib1.pyf @@ -0,0 +1,12 @@ +! -*- f90 -*- +python module fib2 ! in + interface ! in :fib2 + subroutine fib(a,n) ! in :fib2:fib1.f + real*8 dimension(n) :: a + integer optional,check(len(a)>=n),depend(a) :: n=len(a) + end subroutine fib + end interface +end python module fib2 + +! This file was auto-generated with f2py (version:2.28.198-1366). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/numpy/f2py/docs/usersguide/fib2.pyf b/numpy/f2py/docs/usersguide/fib2.pyf new file mode 100644 index 000000000..4a5ae29f1 --- /dev/null +++ b/numpy/f2py/docs/usersguide/fib2.pyf @@ -0,0 +1,9 @@ +! -*- f90 -*- +python module fib2 + interface + subroutine fib(a,n) + real*8 dimension(n),intent(out),depend(n) :: a + integer intent(in) :: n + end subroutine fib + end interface +end python module fib2 diff --git a/numpy/f2py/docs/usersguide/fib3.f b/numpy/f2py/docs/usersguide/fib3.f new file mode 100644 index 000000000..08b050cd2 --- /dev/null +++ b/numpy/f2py/docs/usersguide/fib3.f @@ -0,0 +1,21 @@ +C FILE: FIB3.F + SUBROUTINE FIB(A,N) +C +C CALCULATE FIRST N FIBONACCI NUMBERS +C + INTEGER N + REAL*8 A(N) +Cf2py intent(in) n +Cf2py intent(out) a +Cf2py depend(n) a + DO I=1,N + IF (I.EQ.1) THEN + A(I) = 0.0D0 + ELSEIF (I.EQ.2) THEN + A(I) = 1.0D0 + ELSE + A(I) = A(I-1) + A(I-2) + ENDIF + ENDDO + END +C END FILE FIB3.F diff --git a/numpy/f2py/docs/usersguide/ftype.f b/numpy/f2py/docs/usersguide/ftype.f new file mode 100644 index 000000000..cabbb9e2d --- /dev/null +++ b/numpy/f2py/docs/usersguide/ftype.f @@ -0,0 +1,9 @@ +C FILE: FTYPE.F + SUBROUTINE FOO(N) + INTEGER N +Cf2py integer optional,intent(in) :: n = 13 + REAL A,X + COMMON /DATA/ A,X(3) + PRINT*, "IN FOO: N=",N," A=",A," X=[",X(1),X(2),X(3),"]" + END +C END OF FTYPE.F diff --git a/numpy/f2py/docs/usersguide/ftype_session.dat b/numpy/f2py/docs/usersguide/ftype_session.dat new file mode 100644 index 000000000..01f9febaf --- /dev/null +++ b/numpy/f2py/docs/usersguide/ftype_session.dat @@ -0,0 +1,21 @@ +>>> import ftype +>>> print ftype.__doc__ +This module 'ftype' is auto-generated with f2py (version:2.28.198-1366). +Functions: + foo(n=13) +COMMON blocks: + /data/ a,x(3) +. +>>> type(ftype.foo),type(ftype.data) +(<type 'fortran'>, <type 'fortran'>) +>>> ftype.foo() + IN FOO: N= 13 A= 0. X=[ 0. 0. 0.] +>>> ftype.data.a = 3 +>>> ftype.data.x = [1,2,3] +>>> ftype.foo() + IN FOO: N= 13 A= 3. X=[ 1. 2. 3.] +>>> ftype.data.x[1] = 45 +>>> ftype.foo(24) + IN FOO: N= 24 A= 3. X=[ 1. 45. 3.] +>>> ftype.data.x +array([ 1., 45., 3.],'f') diff --git a/numpy/f2py/docs/usersguide/index.txt b/numpy/f2py/docs/usersguide/index.txt new file mode 100644 index 000000000..9fafb99fb --- /dev/null +++ b/numpy/f2py/docs/usersguide/index.txt @@ -0,0 +1,1772 @@ +.. -*- rest -*- + +////////////////////////////////////////////////////////////////////// + F2PY Users Guide and Reference Manual +////////////////////////////////////////////////////////////////////// + +:Author: Pearu Peterson +:Contact: pearu@cens.ioc.ee +:Web site: http://cens.ioc.ee/projects/f2py2e/ +:Date: $Date: 2005/04/02 10:03:26 $ +:Revision: $Revision: 1.27 $ + + +.. section-numbering:: + +.. Contents:: + + +================ + Introduction +================ + +The purpose of the F2PY_ --*Fortran to Python interface generator*-- +project is to provide a connection between Python and Fortran +languages. F2PY is a Python_ package (with a command line tool +``f2py`` and a module ``f2py2e``) that facilitates creating/building +Python C/API extension modules that make it possible + +* to call Fortran 77/90/95 external subroutines and Fortran 90/95 + module subroutines as well as C functions; +* to access Fortran 77 ``COMMON`` blocks and Fortran 90/95 module data, + including allocatable arrays + +from Python. See F2PY_ web site for more information and installation +instructions. + +====================================== + Three ways to wrap - getting started +====================================== + +Wrapping Fortran or C functions to Python using F2PY consists of the +following steps: + +* Creating the so-called signature file that contains descriptions of + wrappers to Fortran or C functions, also called as signatures of the + functions. In the case of Fortran routines, F2PY can create initial + signature file by scanning Fortran source codes and + catching all relevant information needed to create wrapper + functions. + +* Optionally, F2PY created signature files can be edited to optimize + wrappers functions, make them "smarter" and more "Pythonic". + +* F2PY reads a signature file and writes a Python C/API module containing + Fortran/C/Python bindings. + +* F2PY compiles all sources and builds an extension module containing + the wrappers. In building extension modules, F2PY uses + ``scipy_distutils`` that supports a number of Fortran 77/90/95 + compilers, including Gnu, Intel, + Sun Fortre, SGI MIPSpro, Absoft, NAG, Compaq etc. compilers. + +Depending on a particular situation, these steps can be carried out +either by just in one command or step-by-step, some steps can be +ommited or combined with others. + +Below I'll describe three typical approaches of using F2PY. +The following `example Fortran 77 code`__ will be used for +illustration: + +.. include:: fib1.f + :literal: + +__ fib1.f + +The quick way +============== + +The quickest way to wrap the Fortran subroutine ``FIB`` to Python is +to run + +:: + + f2py -c fib1.f -m fib1 + +This command builds (see ``-c`` flag, execute ``f2py`` without +arguments to see the explanation of command line options) an extension +module ``fib1.so`` (see ``-m`` flag) to the current directory. Now, in +Python the Fortran subroutine ``FIB`` is accessible via ``fib1.fib``:: + + >>> import Numeric + >>> import fib1 + >>> print fib1.fib.__doc__ + fib - Function signature: + fib(a,[n]) + Required arguments: + a : input rank-1 array('d') with bounds (n) + Optional arguments: + n := len(a) input int + + >>> a=Numeric.zeros(8,'d') + >>> fib1.fib(a) + >>> print a + [ 0. 1. 1. 2. 3. 5. 8. 13.] + +.. topic:: Comments + + * Note that F2PY found that the second argument ``n`` is the + dimension of the first array argument ``a``. Since by default all + arguments are input-only arguments, F2PY concludes that ``n`` can + be optional with the default value ``len(a)``. + + * One can use different values for optional ``n``:: + + >>> a1=Numeric.zeros(8,'d') + >>> fib1.fib(a1,6) + >>> print a1 + [ 0. 1. 1. 2. 3. 5. 0. 0.] + + but an exception is raised when it is incompatible with the input + array ``a``:: + + >>> fib1.fib(a,10) + fib:n=10 + Traceback (most recent call last): + File "<stdin>", line 1, in ? + fib.error: (len(a)>=n) failed for 1st keyword n + >>> + + This demonstrates one of the useful features in F2PY, that it, + F2PY implements basic compatibility checks between related + arguments in order to avoid any unexpected crashes. + + * When a Numeric array, that is Fortran contiguous and has a typecode + corresponding to presumed Fortran type, is used as an input array + argument, then its C pointer is directly passed to Fortran. + + Otherwise F2PY makes a contiguous copy (with a proper typecode) of + the input array and passes C pointer of the copy to Fortran + subroutine. As a result, any possible changes to the (copy of) + input array have no effect to the original argument, as + demonstrated below:: + + >>> a=Numeric.ones(8,'i') + >>> fib1.fib(a) + >>> print a + [1 1 1 1 1 1 1 1] + + Clearly, this is not an expected behaviour. The fact that the + above example worked with ``typecode='d'`` is considered + accidental. + + F2PY provides ``intent(inplace)`` attribute that would modify + the attributes of an input array so that any changes made by + Fortran routine will be effective also in input argument. For example, + if one specifies ``intent(inplace) a`` (see below, how), then + the example above would read: + + >>> a=Numeric.ones(8,'i') + >>> fib1.fib(a) + >>> print a + [ 0. 1. 1. 2. 3. 5. 8. 13.] + + However, the recommended way to get changes made by Fortran + subroutine back to python is to use ``intent(out)`` attribute. It + is more efficient and a cleaner solution. + + * The usage of ``fib1.fib`` in Python is very similar to using + ``FIB`` in Fortran. However, using *in situ* output arguments in + Python indicates a poor style as there is no safety mechanism + in Python with respect to wrong argument types. When using Fortran + or C, compilers naturally discover any type mismatches during + compile time but in Python the types must be checked in + runtime. So, using *in situ* output arguments in Python may cause + difficult to find bugs, not to mention that the codes will be less + readable when all required type checks are implemented. + + Though the demonstrated way of wrapping Fortran routines to Python + is very straightforward, it has several drawbacks (see the comments + above). These drawbacks are due to the fact that there is no way + that F2PY can determine what is the acctual intention of one or the + other argument, is it input or output argument, or both, or + something else. So, F2PY conservatively assumes that all arguments + are input arguments by default. + + However, there are ways (see below) how to "teach" F2PY about the + true intentions (among other things) of function arguments; and then + F2PY is able to generate more Pythonic (more explicit, easier to + use, and less error prone) wrappers to Fortran functions. + +The smart way +============== + +Let's apply the steps of wrapping Fortran functions to Python one by +one. + +* First, we create a signature file from ``fib1.f`` by running + + :: + + f2py fib1.f -m fib2 -h fib1.pyf + + The signature file is saved to ``fib1.pyf`` (see ``-h`` flag) and + its contents is shown below. + + .. include:: fib1.pyf + :literal: + +* Next, we'll teach F2PY that the argument ``n`` is a input argument + (use ``intent(in)`` attribute) and that the result, i.e. the + contents of ``a`` after calling Fortran function ``FIB``, should be + returned to Python (use ``intent(out)`` attribute). In addition, an + array ``a`` should be created dynamically using the size given by + the input argument ``n`` (use ``depend(n)`` attribute to indicate + dependence relation). + + The content of a modified version of ``fib1.pyf`` (saved as + ``fib2.pyf``) is as follows: + + .. include:: fib2.pyf + :literal: + +* And finally, we build the extension module by running + + :: + + f2py -c fib2.pyf fib1.f + +In Python:: + + >>> import fib2 + >>> print fib2.fib.__doc__ + fib - Function signature: + a = fib(n) + Required arguments: + n : input int + Return objects: + a : rank-1 array('d') with bounds (n) + + >>> print fib2.fib(8) + [ 0. 1. 1. 2. 3. 5. 8. 13.] + +.. topic:: Comments + + * Clearly, the signature of ``fib2.fib`` now corresponds to the + intention of Fortran subroutine ``FIB`` more closely: given the + number ``n``, ``fib2.fib`` returns the first ``n`` Fibonacci numbers + as a Numeric array. Also, the new Python signature ``fib2.fib`` + rules out any surprises that we experienced with ``fib1.fib``. + + * Note that by default using single ``intent(out)`` also implies + ``intent(hide)``. Argument that has ``intent(hide)`` attribute + specified, will not be listed in the argument list of a wrapper + function. + +The quick and smart way +======================== + +The "smart way" of wrapping Fortran functions, as explained above, is +suitable for wrapping (e.g. third party) Fortran codes for which +modifications to their source codes are not desirable nor even +possible. + +However, if editing Fortran codes is acceptable, then the generation +of an intermediate signature file can be skipped in most +cases. Namely, F2PY specific attributes can be inserted directly to +Fortran source codes using the so-called F2PY directive. A F2PY +directive defines special comment lines (starting with ``Cf2py``, for +example) which are ignored by Fortran compilers but F2PY interprets +them as normal lines. + +Here is shown a `modified version of the example Fortran code`__, saved +as ``fib3.f``: + +.. include:: fib3.f + :literal: + +__ fib3.f + +Building the extension module can be now carried out in one command:: + + f2py -c -m fib3 fib3.f + +Notice that the resulting wrapper to ``FIB`` is as "smart" as in +previous case:: + + >>> import fib3 + >>> print fib3.fib.__doc__ + fib - Function signature: + a = fib(n) + Required arguments: + n : input int + Return objects: + a : rank-1 array('d') with bounds (n) + + >>> print fib3.fib(8) + [ 0. 1. 1. 2. 3. 5. 8. 13.] + + +================== + Signature file +================== + +The syntax specification for signature files (.pyf files) is borrowed +from the Fortran 90/95 language specification. Almost all Fortran +90/95 standard constructs are understood, both in free and fixed +format (recall that Fortran 77 is a subset of Fortran 90/95). F2PY +introduces also some extensions to Fortran 90/95 language +specification that help designing Fortran to Python interface, make it +more "Pythonic". + +Signature files may contain arbitrary Fortran code (so that Fortran +codes can be considered as signature files). F2PY silently ignores +Fortran constructs that are irrelevant for creating the interface. +However, this includes also syntax errors. So, be careful not making +ones;-). + +In general, the contents of signature files is case-sensitive. When +scanning Fortran codes and writing a signature file, F2PY lowers all +cases automatically except in multi-line blocks or when ``--no-lower`` +option is used. + +The syntax of signature files is overvied below. + +Python module block +===================== + +A signature file may contain one (recommended) or more ``python +module`` blocks. ``python module`` block describes the contents of +a Python/C extension module ``<modulename>module.c`` that F2PY +generates. + +Exception: if ``<modulename>`` contains a substring ``__user__``, then +the corresponding ``python module`` block describes the signatures of +so-called call-back functions (see `Call-back arguments`_). + +A ``python module`` block has the following structure:: + + python module <modulename> + [<usercode statement>]... + [ + interface + <usercode statement> + <Fortran block data signatures> + <Fortran/C routine signatures> + end [interface] + ]... + [ + interface + module <F90 modulename> + [<F90 module data type declarations>] + [<F90 module routine signatures>] + end [module [<F90 modulename>]] + end [interface] + ]... + end [python module [<modulename>]] + +Here brackets ``[]`` indicate a optional part, dots ``...`` indicate +one or more of a previous part. So, ``[]...`` reads zero or more of a +previous part. + + +Fortran/C routine signatures +============================= + +The signature of a Fortran routine has the following structure:: + + [<typespec>] function | subroutine <routine name> \ + [ ( [<arguments>] ) ] [ result ( <entityname> ) ] + [<argument/variable type declarations>] + [<argument/variable attribute statements>] + [<use statements>] + [<common block statements>] + [<other statements>] + end [ function | subroutine [<routine name>] ] + +From a Fortran routine signature F2PY generates a Python/C extension +function that has the following signature:: + + def <routine name>(<required arguments>[,<optional arguments>]): + ... + return <return variables> + +The signature of a Fortran block data has the following structure:: + + block data [ <block data name> ] + [<variable type declarations>] + [<variable attribute statements>] + [<use statements>] + [<common block statements>] + [<include statements>] + end [ block data [<block data name>] ] + +Type declarations +------------------- + + The definition of the ``<argument/variable type declaration>`` part + is + + :: + + <typespec> [ [<attrspec>] :: ] <entitydecl> + + where + + :: + + <typespec> := byte | character [<charselector>] + | complex [<kindselector>] | real [<kindselector>] + | double complex | double precision + | integer [<kindselector>] | logical [<kindselector>] + + <charselector> := * <charlen> + | ( [len=] <len> [ , [kind=] <kind>] ) + | ( kind= <kind> [ , len= <len> ] ) + <kindselector> := * <intlen> | ( [kind=] <kind> ) + + <entitydecl> := <name> [ [ * <charlen> ] [ ( <arrayspec> ) ] + | [ ( <arrayspec> ) ] * <charlen> ] + | [ / <init_expr> / | = <init_expr> ] \ + [ , <entitydecl> ] + + and + + + ``<attrspec>`` is a comma separated list of attributes_; + + + ``<arrayspec>`` is a comma separated list of dimension bounds; + + + ``<init_expr>`` is a `C expression`__. + + + ``<intlen>`` may be negative integer for ``integer`` type + specifications. In such cases ``integer*<negintlen>`` represents + unsigned C integers. + +__ `C expressions`_ + + If an argument has no ``<argument type declaration>``, its type is + determined by applying ``implicit`` rules to its name. + + +Statements +------------ + +Attribute statements: + + The ``<argument/variable attribute statement>`` is + ``<argument/variable type declaration>`` without ``<typespec>``. + In addition, in an attribute statement one cannot use other + attributes, also ``<entitydecl>`` can be only a list of names. + +Use statements: + + The definition of the ``<use statement>`` part is + + :: + + use <modulename> [ , <rename_list> | , ONLY : <only_list> ] + + where + + :: + + <rename_list> := <local_name> => <use_name> [ , <rename_list> ] + + Currently F2PY uses ``use`` statement only for linking call-back + modules and ``external`` arguments (call-back functions), see + `Call-back arguments`_. + +Common block statements: + + The definition of the ``<common block statement>`` part is + + :: + + common / <common name> / <shortentitydecl> + + where + + :: + + <shortentitydecl> := <name> [ ( <arrayspec> ) ] [ , <shortentitydecl> ] + + One ``python module`` block should not contain two or more + ``common`` blocks with the same name. Otherwise, the latter ones are + ignored. The types of variables in ``<shortentitydecl>`` are defined + using ``<argument type declarations>``. Note that the corresponding + ``<argument type declarations>`` may contain array specifications; + then you don't need to specify these in ``<shortentitydecl>``. + +Other statements: + + The ``<other statement>`` part refers to any other Fortran language + constructs that are not described above. F2PY ignores most of them + except + + + ``call`` statements and function calls of ``external`` arguments + (`more details`__?); + +__ external_ + + + ``include`` statements + + :: + + include '<filename>' + include "<filename>" + + If a file ``<filename>`` does not exist, the ``include`` + statement is ignored. Otherwise, the file ``<filename>`` is + included to a signature file. ``include`` statements can be used + in any part of a signature file, also outside the Fortran/C + routine signature blocks. + + + ``implicit`` statements + + :: + + implicit none + implicit <list of implicit maps> + + where + + :: + + <implicit map> := <typespec> ( <list of letters or range of letters> ) + + Implicit rules are used to deterimine the type specification of + a variable (from the first-letter of its name) if the variable + is not defined using ``<variable type declaration>``. Default + implicit rule is given by + + :: + + implicit real (a-h,o-z,$_), integer (i-m) + + + ``entry`` statements + + :: + + entry <entry name> [([<arguments>])] + + F2PY generates wrappers to all entry names using the signature + of the routine block. + + Tip: ``entry`` statement can be used to describe the signature + of an arbitrary routine allowing F2PY to generate a number of + wrappers from only one routine block signature. There are few + restrictions while doing this: ``fortranname`` cannot be used, + ``callstatement`` and ``callprotoargument`` can be used only if + they are valid for all entry routines, etc. + + In addition, F2PY introduces the following statements: + + + ``threadsafe`` + Use ``Py_BEGIN_ALLOW_THREADS .. Py_END_ALLOW_THREADS`` block + around the call to Fortran/C function. + + + ``callstatement <C-expr|multi-line block>`` + Replace F2PY generated call statement to Fortran/C function with + ``<C-expr|multi-line block>``. The wrapped Fortran/C function + is available as ``(*f2py_func)``. To raise an exception, set + ``f2py_success = 0`` in ``<C-expr|multi-line block>``. + + + ``callprotoargument <C-typespecs>`` + When ``callstatement`` statement is used then F2PY may not + generate proper prototypes for Fortran/C functions (because + ``<C-expr>`` may contain any function calls and F2PY has no way + to determine what should be the proper prototype). With this + statement you can explicitely specify the arguments of the + corresponding prototype:: + + extern <return type> FUNC_F(<routine name>,<ROUTINE NAME>)(<callprotoargument>); + + + ``fortranname [<acctual Fortran/C routine name>]`` + You can use arbitrary ``<routine name>`` for a given Fortran/C + function. Then you have to specify + ``<acctual Fortran/C routine name>`` with this statement. + + If ``fortranname`` statement is used without + ``<acctual Fortran/C routine name>`` then a dummy wrapper is + generated. + + + ``usercode <multi-line block>`` + When used inside ``python module`` block, then given C code + will be inserted to generated C/API source just before + wrapper function definitions. Here you can define arbitrary + C functions to be used in initialization of optional arguments, + for example. If ``usercode`` is used twise inside ``python + module`` block then the second multi-line block is inserted + after the definition of external routines. + + When used inside ``<routine singature>``, then given C code will + be inserted to the corresponding wrapper function just after + declaring variables but before any C statements. So, ``usercode`` + follow-up can contain both declarations and C statements. + + When used inside the first ``interface`` block, then given C + code will be inserted at the end of the initialization + function of the extension module. Here you can modify extension + modules dictionary. For example, for defining additional + variables etc. + + + ``pymethoddef <multi-line block>`` + Multiline block will be inserted to the definition of + module methods ``PyMethodDef``-array. It must be a + comma-separated list of C arrays (see `Extending and Embedding`__ + Python documentation for details). + ``pymethoddef`` statement can be used only inside + ``python module`` block. + + __ http://www.python.org/doc/current/ext/ext.html + +Attributes +------------ + +The following attributes are used by F2PY: + +``optional`` + The corresponding argument is moved to the end of ``<optional + arguments>`` list. A default value for an optional argument can be + specified ``<init_expr>``, see ``entitydecl`` definition. Note that + the default value must be given as a valid C expression. + + Note that whenever ``<init_expr>`` is used, ``optional`` attribute + is set automatically by F2PY. + + For an optional array argument, all its dimensions must be bounded. + +``required`` + The corresponding argument is considered as a required one. This is + default. You need to specify ``required`` only if there is a need to + disable automatic ``optional`` setting when ``<init_expr>`` is used. + + If Python ``None`` object is used as an required argument, the + argument is treated as optional. That is, in the case of array + argument, the memory is allocated. And if ``<init_expr>`` is given, + the corresponding initialization is carried out. + +``dimension(<arrayspec>)`` + The corresponding variable is considered as an array with given + dimensions in ``<arrayspec>``. + +``intent(<intentspec>)`` + This specifies the "intention" of the corresponding + argument. ``<intentspec>`` is a comma separated list of the + following keys: + + + ``in`` + The argument is considered as an input-only argument. It means + that the value of the argument is passed to Fortran/C function and + that function is expected not to change the value of an argument. + + + ``inout`` + The argument is considered as an input/output or *in situ* + output argument. ``intent(inout)`` arguments can be only + "contiguous" Numeric arrays with proper type and size. Here + "contiguous" can be either in Fortran or C sense. The latter one + coincides with the contiguous concept used in Numeric and is + effective only if ``intent(c)`` is used. Fortran-contiguousness + is assumed by default. + + Using ``intent(inout)`` is generally not recommended, use + ``intent(in,out)`` instead. See also ``intent(inplace)`` attribute. + + + ``inplace`` + The argument is considered as an input/output or *in situ* + output argument. ``intent(inplace)`` arguments must be + Numeric arrays with proper size. If the type of an array is + not "proper" or the array is non-contiguous then the array + will be changed in-place to fix the type and make it contiguous. + + Using ``intent(inplace)`` is generally not recommended either. + For example, when slices have been taken from an + ``intent(inplace)`` argument then after in-place changes, + slices data pointers may point to unallocated memory area. + + + ``out`` + The argument is considered as an return variable. It is appended + to the ``<returned variables>`` list. Using ``intent(out)`` + sets ``intent(hide)`` automatically, unless also + ``intent(in)`` or ``intent(inout)`` were used. + + By default, returned multidimensional arrays are + Fortran-contiguous. If ``intent(c)`` is used, then returned + multi-dimensional arrays are C-contiguous. + + + ``hide`` + The argument is removed from the list of required or optional + arguments. Typically ``intent(hide)`` is used with ``intent(out)`` + or when ``<init_expr>`` completely determines the value of the + argument like in the following example:: + + integer intent(hide),depend(a) :: n = len(a) + real intent(in),dimension(n) :: a + + + ``c`` + The argument is treated as a C scalar or C array argument. In + the case of a scalar argument, its value is passed to C function + as a C scalar argument (recall that Fortran scalar arguments are + actually C pointer arguments). In the case of an array + argument, the wrapper function is assumed to treat + multi-dimensional arrays as C-contiguous arrays. + + There is no need to use ``intent(c)`` for one-dimensional + arrays, no matter if the wrapped function is either a Fortran or + a C function. This is because the concepts of Fortran- and + C-contiguousness overlap in one-dimensional cases. + + If ``intent(c)`` is used as an statement but without entity + declaration list, then F2PY adds ``intent(c)`` attibute to all + arguments. + + Also, when wrapping C functions, one must use ``intent(c)`` + attribute for ``<routine name>`` in order to disable Fortran + specific ``F_FUNC(..,..)`` macros. + + + ``cache`` + The argument is treated as a junk of memory. No Fortran nor C + contiguousness checks are carried out. Using ``intent(cache)`` + makes sense only for array arguments, also in connection with + ``intent(hide)`` or ``optional`` attributes. + + + ``copy`` + Ensure that the original contents of ``intent(in)`` argument is + preserved. Typically used in connection with ``intent(in,out)`` + attribute. F2PY creates an optional argument + ``overwrite_<argument name>`` with the default value ``0``. + + + ``overwrite`` + The original contents of the ``intent(in)`` argument may be + altered by the Fortran/C function. F2PY creates an optional + argument ``overwrite_<argument name>`` with the default value + ``1``. + + + ``out=<new name>`` + Replace the return name with ``<new name>`` in the ``__doc__`` + string of a wrapper function. + + + ``callback`` + Construct an external function suitable for calling Python function + from Fortran. ``intent(callback)`` must be specified before the + corresponding ``external`` statement. If 'argument' is not in + argument list then it will be added to Python wrapper but only + initializing external function. + + Use ``intent(callback)`` in situations where a Fortran/C code + assumes that a user implements a function with given prototype + and links it to an executable. Don't use ``intent(callback)`` + if function appears in the argument list of a Fortran routine. + + With ``intent(hide)`` or ``optional`` attributes specified and + using a wrapper function without specifying the callback argument + in argument list then call-back function is looked in the + namespace of F2PY generated extension module where it can be + set as a module attribute by a user. + + + ``aux`` + Define auxiliary C variable in F2PY generated wrapper function. + Useful to save parameter values so that they can be accessed + in initialization expression of other variables. Note that + ``intent(aux)`` silently implies ``intent(c)``. + + The following rules apply: + + + If no ``intent(in | inout | out | hide)`` is specified, + ``intent(in)`` is assumed. + + ``intent(in,inout)`` is ``intent(in)``. + + ``intent(in,hide)`` or ``intent(inout,hide)`` is + ``intent(hide)``. + + ``intent(out)`` is ``intent(out,hide)`` unless ``intent(in)`` or + ``intent(inout)`` is specified. + + If ``intent(copy)`` or ``intent(overwrite)`` is used, then an + additional optional argument is introduced with a name + ``overwrite_<argument name>`` and a default value 0 or 1, respectively. + + ``intent(inout,inplace)`` is ``intent(inplace)``. + + ``intent(in,inplace)`` is ``intent(inplace)``. + + ``intent(hide)`` disables ``optional`` and ``required``. + +``check([<C-booleanexpr>])`` + Perform consistency check of arguments by evaluating + ``<C-booleanexpr>``; if ``<C-booleanexpr>`` returns 0, an exception + is raised. + + If ``check(..)`` is not used then F2PY generates few standard checks + (e.g. in a case of an array argument, check for the proper shape + and size) automatically. Use ``check()`` to disable checks generated + by F2PY. + +``depend([<names>])`` + This declares that the corresponding argument depends on the values + of variables in the list ``<names>``. For example, ``<init_expr>`` + may use the values of other arguments. Using information given by + ``depend(..)`` attributes, F2PY ensures that arguments are + initialized in a proper order. If ``depend(..)`` attribute is not + used then F2PY determines dependence relations automatically. Use + ``depend()`` to disable dependence relations generated by F2PY. + + When you edit dependence relations that were initially generated by + F2PY, be careful not to break the dependence relations of other + relevant variables. Another thing to watch out is cyclic + dependencies. F2PY is able to detect cyclic dependencies + when constructing wrappers and it complains if any are found. + +``allocatable`` + The corresponding variable is Fortran 90 allocatable array defined + as Fortran 90 module data. + +.. _external: + +``external`` + The corresponding argument is a function provided by user. The + signature of this so-called call-back function can be defined + + - in ``__user__`` module block, + - or by demonstrative (or real, if the signature file is a real Fortran + code) call in the ``<other statements>`` block. + + For example, F2PY generates from + + :: + + external cb_sub, cb_fun + integer n + real a(n),r + call cb_sub(a,n) + r = cb_fun(4) + + the following call-back signatures:: + + subroutine cb_sub(a,n) + real dimension(n) :: a + integer optional,check(len(a)>=n),depend(a) :: n=len(a) + end subroutine cb_sub + function cb_fun(e_4_e) result (r) + integer :: e_4_e + real :: r + end function cb_fun + + The corresponding user-provided Python function are then:: + + def cb_sub(a,[n]): + ... + return + def cb_fun(e_4_e): + ... + return r + + See also ``intent(callback)`` attribute. + +``parameter`` + The corresponding variable is a parameter and it must have a fixed + value. F2PY replaces all parameter occurrences by their + corresponding values. + +Extensions +============ + +F2PY directives +----------------- + +The so-called F2PY directives allow using F2PY signature file +constructs also in Fortran 77/90 source codes. With this feature you +can skip (almost) completely intermediate signature file generations +and apply F2PY directly to Fortran source codes. + +F2PY directive has the following form:: + + <comment char>f2py ... + +where allowed comment characters for fixed and free format Fortran +codes are ``cC*!#`` and ``!``, respectively. Everything that follows +``<comment char>f2py`` is ignored by a compiler but read by F2PY as a +normal Fortran (non-comment) line: + + When F2PY finds a line with F2PY directive, the directive is first + replaced by 5 spaces and then the line is reread. + +For fixed format Fortran codes, ``<comment char>`` must be at the +first column of a file, of course. For free format Fortran codes, +F2PY directives can appear anywhere in a file. + +C expressions +-------------- + +C expressions are used in the following parts of signature files: + +* ``<init_expr>`` of variable initialization; +* ``<C-booleanexpr>`` of the ``check`` attribute; +* ``<arrayspec> of the ``dimension`` attribute; +* ``callstatement`` statement, here also a C multi-line block can be used. + +A C expression may contain: + +* standard C constructs; +* functions from ``math.h`` and ``Python.h``; +* variables from the argument list, presumably initialized before + according to given dependence relations; +* the following CPP macros: + + ``rank(<name>)`` + Returns the rank of an array ``<name>``. + ``shape(<name>,<n>)`` + Returns the ``<n>``-th dimension of an array ``<name>``. + ``len(<name>)`` + Returns the lenght of an array ``<name>``. + ``size(<name>)`` + Returns the size of an array ``<name>``. + ``slen(<name>)`` + Returns the length of a string ``<name>``. + +For initializing an array ``<array name>``, F2PY generates a loop over +all indices and dimensions that executes the following +pseudo-statement:: + + <array name>(_i[0],_i[1],...) = <init_expr>; + +where ``_i[<i>]`` refers to the ``<i>``-th index value and that runs +from ``0`` to ``shape(<array name>,<i>)-1``. + +For example, a function ``myrange(n)`` generated from the following +signature + +:: + + subroutine myrange(a,n) + fortranname ! myrange is a dummy wrapper + integer intent(in) :: n + real*8 intent(c,out),dimension(n),depend(n) :: a = _i[0] + end subroutine myrange + +is equivalent to ``Numeric.arange(n,typecode='d')``. + +.. topic:: Warning! + + F2PY may lower cases also in C expressions when scanning Fortran codes + (see ``--[no]-lower`` option). + +Multi-line blocks +------------------ + +A multi-line block starts with ``'''`` (triple single-quotes) and ends +with ``'''`` in some *strictly* subsequent line. Multi-line blocks can +be used only within .pyf files. The contents of a multi-line block can +be arbitrary (except that it cannot contain ``'''``) and no +transformations (e.g. lowering cases) are applied to it. + +Currently, multi-line blocks can be used in the following constructs: + ++ as a C expression of the ``callstatement`` statement; + ++ as a C type specification of the ``callprotoargument`` statement; + ++ as a C code block of the ``usercode`` statement; + ++ as a list of C arrays of the ``pymethoddef`` statement; + ++ as documentation string. + +================================== +Using F2PY bindings in Python +================================== + +All wrappers (to Fortran/C routines or to common blocks or to Fortran +90 module data) generated by F2PY are exposed to Python as ``fortran`` +type objects. Routine wrappers are callable ``fortran`` type objects +while wrappers to Fortran data have attributes referring to data +objects. + +All ``fortran`` type object have attribute ``_cpointer`` that contains +CObject referring to the C pointer of the corresponding Fortran/C +function or variable in C level. Such CObjects can be used as an +callback argument of F2PY generated functions to bypass Python C/API +layer of calling Python functions from Fortran or C when the +computational part of such functions is implemented in C or Fortran +and wrapped with F2PY (or any other tool capable of providing CObject +of a function). + +.. topic:: Example + + Consider a `Fortran 77 file`__ ``ftype.f``: + + .. include:: ftype.f + :literal: + + and build a wrapper using:: + + f2py -c ftype.f -m ftype + + __ ftype.f + + In Python: + + .. include:: ftype_session.dat + :literal: + + +Scalar arguments +================= + +In general, a scalar argument of a F2PY generated wrapper function can +be ordinary Python scalar (integer, float, complex number) as well as +an arbitrary sequence object (list, tuple, array, string) of +scalars. In the latter case, the first element of the sequence object +is passed to Fortran routine as a scalar argument. + +Note that when type-casting is required and there is possible loss of +information (e.g. when type-casting float to integer or complex to +float), F2PY does not raise any exception. In complex to real +type-casting only the real part of a complex number is used. + +``intent(inout)`` scalar arguments are assumed to be array objects in +order to *in situ* changes to be effective. It is recommended to use +arrays with proper type but also other types work. + +.. topic:: Example + + Consider the following `Fortran 77 code`__: + + .. include:: scalar.f + :literal: + + and wrap it using ``f2py -c -m scalar scalar.f``. + + __ scalar.f + + In Python: + + .. include:: scalar_session.dat + :literal: + + +String arguments +================= + +F2PY generated wrapper functions accept (almost) any Python object as +a string argument, ``str`` is applied for non-string objects. +Exceptions are Numeric arrays that must have type code ``'c'`` or +``'1'`` when used as string arguments. + +A string can have arbitrary length when using it as a string argument +to F2PY generated wrapper function. If the length is greater than +expected, the string is truncated. If the length is smaller that +expected, additional memory is allocated and filled with ``\0``. + +Because Python strings are immutable, an ``intent(inout)`` argument +expects an array version of a string in order to *in situ* changes to +be effective. + +.. topic:: Example + + Consider the following `Fortran 77 code`__: + + .. include:: string.f + :literal: + + and wrap it using ``f2py -c -m mystring string.f``. + + __ string.f + + Python session: + + .. include:: string_session.dat + :literal: + + +Array arguments +================ + +In general, array arguments of F2PY generated wrapper functions accept +arbitrary sequences that can be transformed to Numeric array objects. +An exception is ``intent(inout)`` array arguments that always must be +proper-contiguous and have proper type, otherwise an exception is +raised. Another exception is ``intent(inplace)`` array arguments that +attributes will be changed in-situ if the argument has different type +than expected (see ``intent(inplace)`` attribute for more +information). + +In general, if a Numeric array is proper-contiguous and has a proper +type then it is directly passed to wrapped Fortran/C function. +Otherwise, an element-wise copy of an input array is made and the +copy, being proper-contiguous and with proper type, is used as an +array argument. + +There are two types of proper-contiguous Numeric arrays: + +* Fortran-contiguous arrays when data is stored column-wise, + i.e. indexing of data as stored in memory starts from the lowest + dimension; +* C-contiguous or simply contiguous arrays when data is stored + row-wise, i.e. indexing of data as stored in memory starts from the + highest dimension. + +For one-dimensional arrays these notions coincide. + +For example, an 2x2 array ``A`` is Fortran-contiguous if its elements +are stored in memory in the following order:: + + A[0,0] A[1,0] A[0,1] A[1,1] + +and C-contiguous if the order is as follows:: + + A[0,0] A[0,1] A[1,0] A[1,1] + +To test whether an array is C-contiguous, use ``.iscontiguous()`` +method of Numeric arrays. To test for Fortran-contiguousness, all +F2PY generated extension modules provide a function +``has_column_major_storage(<array>)``. This function is equivalent to +``Numeric.transpose(<array>).iscontiguous()`` but more efficient. + +Usually there is no need to worry about how the arrays are stored in +memory and whether the wrapped functions, being either Fortran or C +functions, assume one or another storage order. F2PY automatically +ensures that wrapped functions get arguments with proper storage +order; the corresponding algorithm is designed to make copies of +arrays only when absolutely necessary. However, when dealing with very +large multi-dimensional input arrays with sizes close to the size of +the physical memory in your computer, then a care must be taken to use +always proper-contiguous and proper type arguments. + +To transform input arrays to column major storage order before passing +them to Fortran routines, use a function +``as_column_major_storage(<array>)`` that is provided by all F2PY +generated extension modules. + +.. topic:: Example + + Consider `Fortran 77 code`__: + + .. include:: array.f + :literal: + + and wrap it using ``f2py -c -m arr array.f -DF2PY_REPORT_ON_ARRAY_COPY=1``. + + __ array.f + + In Python: + + .. include:: array_session.dat + :literal: + +Call-back arguments +==================== + +F2PY supports calling Python functions from Fortran or C codes. + + +.. topic:: Example + + Consider the following `Fortran 77 code`__ + + .. include:: callback.f + :literal: + + and wrap it using ``f2py -c -m callback callback.f``. + + __ callback.f + + In Python: + + .. include:: callback_session.dat + :literal: + +In the above example F2PY was able to guess accurately the signature +of a call-back function. However, sometimes F2PY cannot establish the +signature as one would wish and then the signature of a call-back +function must be modified in the signature file manually. Namely, +signature files may contain special modules (the names of such modules +contain a substring ``__user__``) that collect various signatures of +call-back functions. Callback arguments in routine signatures have +attribute ``external`` (see also ``intent(callback)`` attribute). To +relate a callback argument and its signature in ``__user__`` module +block, use ``use`` statement as illustrated below. The same signature +of a callback argument can be referred in different routine +signatures. + +.. topic:: Example + + We use the same `Fortran 77 code`__ as in previous example but now + we'll pretend that F2PY was not able to guess the signatures of + call-back arguments correctly. First, we create an initial signature + file ``callback2.pyf`` using F2PY:: + + f2py -m callback2 -h callback2.pyf callback.f + + Then modify it as follows + + .. include:: callback2.pyf + :literal: + + Finally, build the extension module using:: + + f2py -c callback2.pyf callback.f + + An example Python session would be identical to the previous example + except that argument names would differ. + + __ callback.f + +Sometimes a Fortran package may require that users provide routines +that the package will use. F2PY can construct an interface to such +routines so that Python functions could be called from Fortran. + +.. topic:: Example + + Consider the following `Fortran 77 subroutine`__ that takes an array + and applies a function ``func`` to its elements. + + .. include:: calculate.f + :literal: + + __ calculate.f + + It is expected that function ``func`` has been defined + externally. In order to use a Python function as ``func``, it must + have an attribute ``intent(callback)`` (it must be specified before + the ``external`` statement). + + Finally, build an extension module using:: + + f2py -c -m foo calculate.f + + In Python: + + .. include:: calculate_session.dat + :literal: + +The function is included as an argument to the python function call to +the FORTRAN subroutine eventhough it was NOT in the FORTRAN subroutine argument +list. The "external" refers to the C function generated by f2py, not the python +function itself. The python function must be supplied to the C function. + +The callback function may also be explicitly set in the module. +Then it is not necessary to pass the function in the argument list to +the FORTRAN function. This may be desired if the FORTRAN function calling +the python callback function is itself called by another FORTRAN function. + +.. topic:: Example + + Consider the following `Fortran 77 subroutine`__. + + .. include:: extcallback.f + :literal: + + __ extcallback.f + + and wrap it using ``f2py -c -m pfromf extcallback.f``. + + In Python: + + .. include:: extcallback_session.dat + :literal: + +Resolving arguments to call-back functions +------------------------------------------ + +F2PY generated interface is very flexible with respect to call-back +arguments. For each call-back argument an additional optional +argument ``<name>_extra_args`` is introduced by F2PY. This argument +can be used to pass extra arguments to user provided call-back +arguments. + +If a F2PY generated wrapper function expects the following call-back +argument:: + + def fun(a_1,...,a_n): + ... + return x_1,...,x_k + +but the following Python function + +:: + + def gun(b_1,...,b_m): + ... + return y_1,...,y_l + +is provided by an user, and in addition, + +:: + + fun_extra_args = (e_1,...,e_p) + +is used, then the following rules are applied when a Fortran or C +function calls the call-back argument ``gun``: + +* If ``p==0`` then ``gun(a_1,...,a_q)`` is called, here + ``q=min(m,n)``. +* If ``n+p<=m`` then ``gun(a_1,...,a_n,e_1,...,e_p)`` is called. +* If ``p<=m<n+p`` then ``gun(a_1,...,a_q,e_1,...,e_p)`` is called, here + ``q=m-p``. +* If ``p>m`` then ``gun(e_1,...,e_m)`` is called. +* If ``n+p`` is less than the number of required arguments to ``gun`` + then an exception is raised. + +The function ``gun`` may return any number of objects as a tuple. Then +following rules are applied: + +* If ``k<l``, then ``y_{k+1},...,y_l`` are ignored. +* If ``k>l``, then only ``x_1,...,x_l`` are set. + + + +Common blocks +============== + +F2PY generates wrappers to ``common`` blocks defined in a routine +signature block. Common blocks are visible by all Fortran codes linked +with the current extension module, but not to other extension modules +(this restriction is due to how Python imports shared libraries). In +Python, the F2PY wrappers to ``common`` blocks are ``fortran`` type +objects that have (dynamic) attributes related to data members of +common blocks. When accessed, these attributes return as Numeric array +objects (multi-dimensional arrays are Fortran-contiguous) that +directly link to data members in common blocks. Data members can be +changed by direct assignment or by in-place changes to the +corresponding array objects. + +.. topic:: Example + + Consider the following `Fortran 77 code`__ + + .. include:: common.f + :literal: + + and wrap it using ``f2py -c -m common common.f``. + + __ common.f + + In Python: + + .. include:: common_session.dat + :literal: + +Fortran 90 module data +======================= + +The F2PY interface to Fortran 90 module data is similar to Fortran 77 +common blocks. + +.. topic:: Example + + Consider the following `Fortran 90 code`__ + + .. include:: moddata.f90 + :literal: + + and wrap it using ``f2py -c -m moddata moddata.f90``. + + __ moddata.f90 + + In Python: + + .. include:: moddata_session.dat + :literal: + +Allocatable arrays +------------------- + +F2PY has basic support for Fortran 90 module allocatable arrays. + +.. topic:: Example + + Consider the following `Fortran 90 code`__ + + .. include:: allocarr.f90 + :literal: + + and wrap it using ``f2py -c -m allocarr allocarr.f90``. + + __ allocarr.f90 + + In Python: + + .. include:: allocarr_session.dat + :literal: + + +=========== +Using F2PY +=========== + +F2PY can be used either as a command line tool ``f2py`` or as a Python +module ``f2py2e``. + +Command ``f2py`` +================= + +When used as a command line tool, ``f2py`` has three major modes, +distinguished by the usage of ``-c`` and ``-h`` switches: + +1. To scan Fortran sources and generate a signature file, use + + :: + + f2py -h <filename.pyf> <options> <fortran files> \ + [[ only: <fortran functions> : ] \ + [ skip: <fortran functions> : ]]... \ + [<fortran files> ...] + + Note that a Fortran source file can contain many routines, and not + necessarily all routines are needed to be used from Python. So, you + can either specify which routines should be wrapped (in ``only: .. :`` + part) or which routines F2PY should ignored (in ``skip: .. :`` part). + + If ``<filename.pyf>`` is specified as ``stdout`` then signatures + are send to standard output instead of a file. + + Among other options (see below), the following options can be used + in this mode: + + ``--overwrite-signature`` + Overwrite existing signature file. + +2. To construct an extension module, use + + :: + + f2py <options> <fortran files> \ + [[ only: <fortran functions> : ] \ + [ skip: <fortran functions> : ]]... \ + [<fortran files> ...] + + The constructed extension module is saved as + ``<modulename>module.c`` to the current directory. + + Here ``<fortran files>`` may also contain signature files. + Among other options (see below), the following options can be used + in this mode: + + ``--debug-capi`` + Add debugging hooks to the extension module. When using this + extension module, various information about the wrapper is printed + to standard output, for example, the values of variables, the + steps taken, etc. + + ``-include'<includefile>'`` + Add a CPP ``#include`` statement to the extension module source. + ``<includefile>`` should be given in one of the following forms:: + + "filename.ext" + <filename.ext> + + The include statement is inserted just before the wrapper + functions. This feature enables using arbitrary C functions + (defined in ``<includefile>``) in F2PY generated wrappers. + + This option is deprecated. Use ``usercode`` statement to specify + C codelets directly in signature filess + + + ``--[no-]wrap-functions`` + + Create Fortran subroutine wrappers to Fortran functions. + ``--wrap-functions`` is default because it ensures maximum + portability and compiler independence. + + ``--include-paths <path1>:<path2>:..`` + Search include files from given directories. + + ``--help-link [<list of resources names>]`` + List system resources found by ``scipy_distutils/system_info.py``. + For example, try ``f2py --help-link lapack_opt``. + +3. To build an extension module, use + + :: + + f2py -c <options> <fortran files> \ + [[ only: <fortran functions> : ] \ + [ skip: <fortran functions> : ]]... \ + [ <fortran/c source files> ] [ <.o, .a, .so files> ] + + If ``<fortran files>`` contains a signature file, then a source for + an extension module is constructed, all Fortran and C sources are + compiled, and finally all object and library files are linked to the + extension module ``<modulename>.so`` which is saved into the current + directory. + + If ``<fortran files>`` does not contain a signature file, then an + extension module is constructed by scanning all Fortran source codes + for routine signatures. + + Among other options (see below) and options described in previous + mode, the following options can be used in this mode: + + ``--help-fcompiler`` + List available Fortran compilers. + ``--help-compiler`` [depreciated] + List available Fortran compilers. + ``--fcompiler=<Vendor>`` + Specify Fortran compiler type by vendor. + ``--f77exec=<path>`` + Specify the path to F77 compiler + ``--fcompiler-exec=<path>`` [depreciated] + Specify the path to F77 compiler + ``--f90exec=<path>`` + Specify the path to F90 compiler + ``--f90compiler-exec=<path>`` [depreciated] + Specify the path to F90 compiler + + ``--f77flags=<string>`` + Specify F77 compiler flags + ``--f90flags=<string>`` + Specify F90 compiler flags + ``--opt=<string>`` + Specify optimization flags + ``--arch=<string>`` + Specify architecture specific optimization flags + ``--noopt`` + Compile without optimization + ``--noarch`` + Compile without arch-dependent optimization + ``--debug`` + Compile with debugging information + + ``-l<libname>`` + Use the library ``<libname>`` when linking. + ``-D<macro>[=<defn=1>]`` + Define macro ``<macro>`` as ``<defn>``. + ``-U<macro>`` + Define macro ``<macro>`` + ``-I<dir>`` + Append directory ``<dir>`` to the list of directories searched for + include files. + ``-L<dir>`` + Add directory ``<dir>`` to the list of directories to be searched + for ``-l``. + + ``link-<resource>`` + + Link extension module with <resource> as defined by + ``scipy_distutils/system_info.py``. E.g. to link with optimized + LAPACK libraries (vecLib on MacOSX, ATLAS elsewhere), use + ``--link-lapack_opt``. See also ``--help-link`` switch. + + When building an extension module, a combination of the following + macros may be required for non-gcc Fortran compilers:: + + -DPREPEND_FORTRAN + -DNO_APPEND_FORTRAN + -DUPPERCASE_FORTRAN + + To test the performance of F2PY generated interfaces, use + ``-DF2PY_REPORT_ATEXIT``. Then a report of various timings is + printed out at the exit of Python. This feature may not work on + all platforms, currently only Linux platform is supported. + + To see whether F2PY generated interface performs copies of array + arguments, use ``-DF2PY_REPORT_ON_ARRAY_COPY=<int>``. When the size + of an array argument is larger than ``<int>``, a message about + the coping is sent to ``stderr``. + +Other options: + +``-m <modulename>`` + Name of an extension module. Default is ``untitled``. Don't use this option + if a signature file (*.pyf) is used. +``--[no-]lower`` + Do [not] lower the cases in ``<fortran files>``. By default, + ``--lower`` is assumed with ``-h`` switch, and ``--no-lower`` + without the ``-h`` switch. +``--build-dir <dirname>`` + All F2PY generated files are created in ``<dirname>``. Default is + ``tempfile.mktemp()``. +``--quiet`` + Run quietly. +``--verbose`` + Run with extra verbosity. +``-v`` + Print f2py version ID and exit. + +Execute ``f2py`` without any options to get an up-to-date list of +available options. + +Python module ``f2py2e`` +========================= + +.. topic:: Warning + + The current Python interface to ``f2py2e`` module is not mature and + may change in future depending on users needs. + +The following functions are provided by the ``f2py2e`` module: + +``run_main(<list>)`` + Equivalent to running:: + + f2py <args> + + where ``<args>=string.join(<list>,' ')``, but in Python. Unless + ``-h`` is used, this function returns a dictionary containing + information on generated modules and their dependencies on source + files. For example, the command ``f2py -m scalar scalar.f`` can be + executed from Python as follows + + .. include:: run_main_session.dat + :literal: + + You cannot build extension modules with this function, that is, + using ``-c`` is not allowed. Use ``compile`` command instead, see + below. + +``compile(source, modulename='untitled', extra_args='', verbose=1, source_fn=None)`` + + Build extension module from Fortran 77 source string ``source``. + Return 0 if successful. + Note that this function actually calls ``f2py -c ..`` from shell to + ensure safety of the current Python process. + For example, + + .. include:: compile_session.dat + :literal: + +========================== +Using ``scipy_distutils`` +========================== + +``scipy_distutils`` is part of the SciPy_ project and aims to extend +standard Python ``distutils`` to deal with Fortran sources and F2PY +signature files, e.g. compile Fortran sources, call F2PY to construct +extension modules, etc. + +.. topic:: Example + + Consider the following `setup file`__: + + .. include:: setup_example.py + :literal: + + Running + + :: + + python setup_example.py build + + will build two extension modules ``scalar`` and ``fib2`` to the + build directory. + + __ setup_example.py + +``scipy_distutils`` extends ``distutils`` with the following features: + +* ``Extension`` class argument ``sources`` may contain Fortran source + files. In addition, the list ``sources`` may contain at most one + F2PY signature file, and then the name of an Extension module must + match with the ``<modulename>`` used in signature file. It is + assumed that an F2PY signature file contains exactly one ``python + module`` block. + + If ``sources`` does not contain a signature files, then F2PY is used + to scan Fortran source files for routine signatures to construct the + wrappers to Fortran codes. + + Additional options to F2PY process can be given using ``Extension`` + class argument ``f2py_options``. + +``scipy_distutils`` 0.2.2 and up +================================ + +* The following new ``distutils`` commands are defined: + + ``build_src`` + to construct Fortran wrapper extension modules, among many other things. + ``config_fc`` + to change Fortran compiler options + + as well as ``build_ext`` and ``build_clib`` commands are enhanced + to support Fortran sources. + + Run + + :: + + python <setup.py file> config_fc build_src build_ext --help + + to see available options for these commands. + +* When building Python packages containing Fortran sources, then one + can choose different Fortran compilers by using ``build_ext`` + command option ``--fcompiler=<Vendor>``. Here ``<Vendor>`` can be one of the + following names:: + + absoft sun mips intel intelv intele intelev nag compaq compaqv gnu vast pg hpux + + See ``scipy_distutils/fcompiler.py`` for up-to-date list of + supported compilers or run + + :: + + f2py -c --help-fcompiler + +``scipy_distutils`` pre 0.2.2 +============================= + +* The following new ``distutils`` commands are defined: + + ``build_flib`` + to build f77/f90 libraries used by Python extensions; + ``run_f2py`` + to construct Fortran wrapper extension modules. + + Run + + :: + + python <setup.py file> build_flib run_f2py --help + + to see available options for these commands. + +* When building Python packages containing Fortran sources, then one + can choose different Fortran compilers either by using ``build_flib`` + command option ``--fcompiler=<Vendor>`` or by defining environment + variable ``FC_VENDOR=<Vendor>``. Here ``<Vendor>`` can be one of the + following names:: + + Absoft Sun SGI Intel Itanium NAG Compaq Digital Gnu VAST PG + + See ``scipy_distutils/command/build_flib.py`` for up-to-date list of + supported compilers. + +====================== + Extended F2PY usages +====================== + +Adding self-written functions to F2PY generated modules +======================================================= + +Self-written Python C/API functions can be defined inside +signature files using ``usercode`` and ``pymethoddef`` statements +(they must be used inside the ``python module`` block). For +example, the following signature file ``spam.pyf`` + +.. include:: spam.pyf + :literal: + +wraps the C library function ``system()``:: + + f2py -c spam.pyf + +In Python: + +.. include:: spam_session.dat + :literal: + +Modifying the dictionary of a F2PY generated module +=================================================== + +The following example illustrates how to add an user-defined +variables to a F2PY generated extension module. Given the following +signature file + +.. include:: var.pyf + :literal: + +compile it as ``f2py -c var.pyf``. + +Notice that the second ``usercode`` statement must be defined inside +an ``interface`` block and where the module dictionary is available through +the variable ``d`` (see ``f2py var.pyf``-generated ``varmodule.c`` for +additional details). + +In Python: + +.. include:: var_session.dat + :literal: + +.. References + ========== +.. _F2PY: http://cens.ioc.ee/projects/f2py2e/ +.. _Python: http://www.python.org/ +.. _NumPy: http://www.numpy.org/ +.. _SciPy: http://www.scipy.org/ diff --git a/numpy/f2py/docs/usersguide/moddata.f90 b/numpy/f2py/docs/usersguide/moddata.f90 new file mode 100644 index 000000000..0e98f0467 --- /dev/null +++ b/numpy/f2py/docs/usersguide/moddata.f90 @@ -0,0 +1,18 @@ +module mod + integer i + integer :: x(4) + real, dimension(2,3) :: a + real, allocatable, dimension(:,:) :: b +contains + subroutine foo + integer k + print*, "i=",i + print*, "x=[",x,"]" + print*, "a=[" + print*, "[",a(1,1),",",a(1,2),",",a(1,3),"]" + print*, "[",a(2,1),",",a(2,2),",",a(2,3),"]" + print*, "]" + print*, "Setting a(1,2)=a(1,2)+3" + a(1,2) = a(1,2)+3 + end subroutine foo +end module mod diff --git a/numpy/f2py/docs/usersguide/moddata_session.dat b/numpy/f2py/docs/usersguide/moddata_session.dat new file mode 100644 index 000000000..1ec212f8b --- /dev/null +++ b/numpy/f2py/docs/usersguide/moddata_session.dat @@ -0,0 +1,23 @@ +>>> import moddata +>>> print moddata.mod.__doc__ +i - 'i'-scalar +x - 'i'-array(4) +a - 'f'-array(2,3) +foo - Function signature: + foo() + + +>>> moddata.mod.i = 5 +>>> moddata.mod.x[:2] = [1,2] +>>> moddata.mod.a = [[1,2,3],[4,5,6]] +>>> moddata.mod.foo() + i= 5 + x=[ 1 2 0 0 ] + a=[ + [ 1.000000 , 2.000000 , 3.000000 ] + [ 4.000000 , 5.000000 , 6.000000 ] + ] + Setting a(1,2)=a(1,2)+3 +>>> moddata.mod.a # a is Fortran-contiguous +array([[ 1., 5., 3.], + [ 4., 5., 6.]],'f') diff --git a/numpy/f2py/docs/usersguide/run_main_session.dat b/numpy/f2py/docs/usersguide/run_main_session.dat new file mode 100644 index 000000000..29ecc3dfe --- /dev/null +++ b/numpy/f2py/docs/usersguide/run_main_session.dat @@ -0,0 +1,14 @@ +>>> import f2py2e +>>> r=f2py2e.run_main(['-m','scalar','docs/usersguide/scalar.f']) +Reading fortran codes... + Reading file 'docs/usersguide/scalar.f' +Post-processing... + Block: scalar + Block: FOO +Building modules... + Building module "scalar"... + Wrote C/API module "scalar" to file "./scalarmodule.c" +>>> print r +{'scalar': {'h': ['/home/users/pearu/src_cvs/f2py2e/src/fortranobject.h'], + 'csrc': ['./scalarmodule.c', + '/home/users/pearu/src_cvs/f2py2e/src/fortranobject.c']}} diff --git a/numpy/f2py/docs/usersguide/scalar.f b/numpy/f2py/docs/usersguide/scalar.f new file mode 100644 index 000000000..c22f639ed --- /dev/null +++ b/numpy/f2py/docs/usersguide/scalar.f @@ -0,0 +1,12 @@ +C FILE: SCALAR.F + SUBROUTINE FOO(A,B) + REAL*8 A, B +Cf2py intent(in) a +Cf2py intent(inout) b + PRINT*, " A=",A," B=",B + PRINT*, "INCREMENT A AND B" + A = A + 1D0 + B = B + 1D0 + PRINT*, "NEW A=",A," B=",B + END +C END OF FILE SCALAR.F diff --git a/numpy/f2py/docs/usersguide/scalar_session.dat b/numpy/f2py/docs/usersguide/scalar_session.dat new file mode 100644 index 000000000..4fe8c03b1 --- /dev/null +++ b/numpy/f2py/docs/usersguide/scalar_session.dat @@ -0,0 +1,21 @@ +>>> import scalar +>>> print scalar.foo.__doc__ +foo - Function signature: + foo(a,b) +Required arguments: + a : input float + b : in/output rank-0 array(float,'d') + +>>> scalar.foo(2,3) + A= 2. B= 3. + INCREMENT A AND B + NEW A= 3. B= 4. +>>> import Numeric +>>> a=Numeric.array(2) # these are integer rank-0 arrays +>>> b=Numeric.array(3) +>>> scalar.foo(a,b) + A= 2. B= 3. + INCREMENT A AND B + NEW A= 3. B= 4. +>>> print a,b # note that only b is changed in situ +2 4
\ No newline at end of file diff --git a/numpy/f2py/docs/usersguide/setup_example.py b/numpy/f2py/docs/usersguide/setup_example.py new file mode 100644 index 000000000..a7d27403a --- /dev/null +++ b/numpy/f2py/docs/usersguide/setup_example.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# File: setup_example.py + +from scipy_distutils.core import Extension + +ext1 = Extension(name = 'scalar', + sources = ['scalar.f']) +ext2 = Extension(name = 'fib2', + sources = ['fib2.pyf','fib1.f']) + +if __name__ == "__main__": + from scipy_distutils.core import setup + setup(name = 'f2py_example', + description = "F2PY Users Guide examples", + author = "Pearu Peterson", + author_email = "pearu@cens.ioc.ee", + ext_modules = [ext1,ext2] + ) +# End of setup_example.py diff --git a/numpy/f2py/docs/usersguide/spam.pyf b/numpy/f2py/docs/usersguide/spam.pyf new file mode 100644 index 000000000..21ea18b77 --- /dev/null +++ b/numpy/f2py/docs/usersguide/spam.pyf @@ -0,0 +1,19 @@ +! -*- f90 -*- +python module spam + usercode ''' + static char doc_spam_system[] = "Execute a shell command."; + static PyObject *spam_system(PyObject *self, PyObject *args) + { + char *command; + int sts; + + if (!PyArg_ParseTuple(args, "s", &command)) + return NULL; + sts = system(command); + return Py_BuildValue("i", sts); + } + ''' + pymethoddef ''' + {"system", spam_system, METH_VARARGS, doc_spam_system}, + ''' +end python module spam diff --git a/numpy/f2py/docs/usersguide/spam_session.dat b/numpy/f2py/docs/usersguide/spam_session.dat new file mode 100644 index 000000000..7f99d13f9 --- /dev/null +++ b/numpy/f2py/docs/usersguide/spam_session.dat @@ -0,0 +1,5 @@ +>>> import spam +>>> status = spam.system('whoami') +pearu +>> status = spam.system('blah') +sh: line 1: blah: command not found
\ No newline at end of file diff --git a/numpy/f2py/docs/usersguide/string.f b/numpy/f2py/docs/usersguide/string.f new file mode 100644 index 000000000..9246f02e7 --- /dev/null +++ b/numpy/f2py/docs/usersguide/string.f @@ -0,0 +1,21 @@ +C FILE: STRING.F + SUBROUTINE FOO(A,B,C,D) + CHARACTER*5 A, B + CHARACTER*(*) C,D +Cf2py intent(in) a,c +Cf2py intent(inout) b,d + PRINT*, "A=",A + PRINT*, "B=",B + PRINT*, "C=",C + PRINT*, "D=",D + PRINT*, "CHANGE A,B,C,D" + A(1:1) = 'A' + B(1:1) = 'B' + C(1:1) = 'C' + D(1:1) = 'D' + PRINT*, "A=",A + PRINT*, "B=",B + PRINT*, "C=",C + PRINT*, "D=",D + END +C END OF FILE STRING.F diff --git a/numpy/f2py/docs/usersguide/string_session.dat b/numpy/f2py/docs/usersguide/string_session.dat new file mode 100644 index 000000000..64ebcb3f4 --- /dev/null +++ b/numpy/f2py/docs/usersguide/string_session.dat @@ -0,0 +1,27 @@ +>>> import mystring +>>> print mystring.foo.__doc__ +foo - Function signature: + foo(a,b,c,d) +Required arguments: + a : input string(len=5) + b : in/output rank-0 array(string(len=5),'c') + c : input string(len=-1) + d : in/output rank-0 array(string(len=-1),'c') + +>>> import Numeric +>>> a=Numeric.array('123') +>>> b=Numeric.array('123') +>>> c=Numeric.array('123') +>>> d=Numeric.array('123') +>>> mystring.foo(a,b,c,d) + A=123 + B=123 + C=123 + D=123 + CHANGE A,B,C,D + A=A23 + B=B23 + C=C23 + D=D23 +>>> a.tostring(),b.tostring(),c.tostring(),d.tostring() +('123', 'B23', '123', 'D23')
\ No newline at end of file diff --git a/numpy/f2py/docs/usersguide/var.pyf b/numpy/f2py/docs/usersguide/var.pyf new file mode 100644 index 000000000..8275ff3af --- /dev/null +++ b/numpy/f2py/docs/usersguide/var.pyf @@ -0,0 +1,11 @@ +! -*- f90 -*- +python module var + usercode ''' + int BAR = 5; + ''' + interface + usercode ''' + PyDict_SetItemString(d,"BAR",PyInt_FromLong(BAR)); + ''' + end interface +end python module diff --git a/numpy/f2py/docs/usersguide/var_session.dat b/numpy/f2py/docs/usersguide/var_session.dat new file mode 100644 index 000000000..fb0f798bf --- /dev/null +++ b/numpy/f2py/docs/usersguide/var_session.dat @@ -0,0 +1,3 @@ +>>> import var +>>> var.BAR +5
\ No newline at end of file diff --git a/numpy/f2py/f2py.1 b/numpy/f2py/f2py.1 new file mode 100644 index 000000000..3b9f054af --- /dev/null +++ b/numpy/f2py/f2py.1 @@ -0,0 +1,209 @@ +.TH "F2PY" 1 +.SH NAME +f2py \- Fortran to Python interface generator +.SH SYNOPSIS +(1) To construct extension module sources: + +.B f2py +[<options>] <fortran files> [[[only:]||[skip:]] <fortran functions> ] [: <fortran files> ...] + +(2) To compile fortran files and build extension modules: + +.B f2py +-c [<options>, <config_fc options>, <extra options>] <fortran files> + +(3) To generate signature files: + +.B f2py +-h <filename.pyf> ...< same options as in (1) > +.SH DESCRIPTION +This program generates a Python C/API file (<modulename>module.c) +that contains wrappers for given Fortran or C functions so that they +can be called from Python. +With the -c option the corresponding +extension modules are built. +.SH OPTIONS +.TP +.B \-h <filename> +Write signatures of the fortran routines to file <filename> and +exit. You can then edit <filename> and use it instead of <fortran +files>. If <filename>==stdout then the signatures are printed to +stdout. +.TP +.B <fortran functions> +Names of fortran routines for which Python C/API functions will be +generated. Default is all that are found in <fortran files>. +.TP +.B skip: +Ignore fortran functions that follow until `:'. +.TP +.B only: +Use only fortran functions that follow until `:'. +.TP +.B : +Get back to <fortran files> mode. +.TP +.B \-m <modulename> +Name of the module; f2py generates a Python/C API file +<modulename>module.c or extension module <modulename>. Default is +\'untitled\'. +.TP +.B \-\-[no\-]lower +Do [not] lower the cases in <fortran files>. By default, --lower is +assumed with -h key, and --no-lower without -h key. +.TP +.B \-\-build\-dir <dirname> +All f2py generated files are created in <dirname>. Default is tempfile.mktemp(). +.TP +.B \-\-overwrite\-signature +Overwrite existing signature file. +.TP +.B \-\-[no\-]latex\-doc +Create (or not) <modulename>module.tex. Default is --no-latex-doc. +.TP +.B \-\-short\-latex +Create 'incomplete' LaTeX document (without commands \\documentclass, +\\tableofcontents, and \\begin{document}, \\end{document}). +.TP +.B \-\-[no\-]rest\-doc +Create (or not) <modulename>module.rst. Default is --no-rest-doc. +.TP +.B \-\-debug\-capi +Create C/API code that reports the state of the wrappers during +runtime. Useful for debugging. +.TP +.B \-include\'<includefile>\' +Add CPP #include statement to the C/API code. <includefile> should be +in the format of either `"filename.ext"' or `<filename.ext>'. As a +result <includefile> will be included just before wrapper functions +part in the C/API code. The option is depreciated, use `usercode` +statement in signature files instead. +.TP +.B \-\-[no\-]wrap\-functions +Create Fortran subroutine wrappers to Fortran 77 +functions. --wrap-functions is default because it ensures maximum +portability/compiler independence. +.TP +.B \-\-help\-link [..] +List system resources found by system_info.py. [..] may contain +a list of resources names. See also --link-<resource> switch below. +.TP +.B \-\-quiet +Run quietly. +.TP +.B \-\-verbose +Run with extra verbosity. +.TP +.B \-v +Print f2py version ID and exit. +.TP +.B \-\-include_paths path1:path2:... +Search include files (that f2py will scan) from the given directories. +.SH "CONFIG_FC OPTIONS" +The following options are effective only when -c switch is used. +.TP +.B \-\-help-compiler +List available Fortran compilers [DEPRECIATED]. +.TP +.B \-\-fcompiler=<name> +Specify Fortran compiler type by vendor. +.TP +.B \-\-compiler=<name> +Specify C compiler type (as defined by distutils) +.TP +.B \-\-fcompiler-exec=<path> +Specify the path to F77 compiler [DEPRECIATED]. +.TP +.B \-\-f90compiler\-exec=<path> +Specify the path to F90 compiler [DEPRECIATED]. +.TP +.B \-\-help\-fcompiler +List available Fortran compilers and exit. +.TP +.B \-\-f77exec=<path> +Specify the path to F77 compiler. +.TP +.B \-\-f90exec=<path> +Specify the path to F90 compiler. +.TP +.B \-\-f77flags="..." +Specify F77 compiler flags. +.TP +.B \-\-f90flags="..." +Specify F90 compiler flags. +.TP +.B \-\-opt="..." +Specify optimization flags. +.TP +.B \-\-arch="..." +Specify architecture specific optimization flags. +.TP +.B \-\-noopt +Compile without optimization. +.TP +.B \-\-noarch +Compile without arch-dependent optimization. +.TP +.B \-\-debug +Compile with debugging information. +.SH "EXTRA OPTIONS" +The following options are effective only when -c switch is used. +.TP +.B \-\-link-<resource> +Link extension module with <resource> as defined by +scipy_distutils/system_info.py. E.g. to link with optimized LAPACK +libraries (vecLib on MacOSX, ATLAS elsewhere), use +--link-lapack_opt. See also --help-link switch. + +.TP +.B -L/path/to/lib/ -l<libname> +.TP +.B -D<define> -U<name> -I/path/to/include/ +.TP +.B <filename>.o <filename>.so <filename>.a + +.TP +.B -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN -DUNDERSCORE_G77 +Macros that might be required with non-gcc Fortran compilers. + +.TP +.B -DF2PY_REPORT_ATEXIT +To print out a performance report of F2PY interface when python +exits. Available for Linux. + +.TP +.B -DF2PY_REPORT_ON_ARRAY_COPY=<int> +To send a message to stderr whenever F2PY interface makes a copy of an +array. Integer <int> sets the threshold for array sizes when a message +should be shown. + +.SH REQUIREMENTS +Python 1.5.2 or higher (2.x is supported). + +Numerical Python 13 or higher (20.x,21.x,22.x,23.x are supported). + +Optional Numarray 0.9 or higher partially supported. + +scipy_distutils from Scipy (can be downloaded from F2PY homepage) +.SH "SEE ALSO" +python(1) +.SH BUGS +For instructions on reporting bugs, see + + http://cens.ioc.ee/projects/f2py2e/FAQ.html +.SH AUTHOR +Pearu Peterson <pearu@cens.ioc.ee> +.SH "INTERNET RESOURCES" +Main website: http://cens.ioc.ee/projects/f2py2e/ + +User's Guide: http://cens.ioc.ee/projects/f2py2e/usersguide/ + +Mailing list: http://cens.ioc.ee/mailman/listinfo/f2py-users/ + +Scipy website: http://www.scipy.org +.SH COPYRIGHT +Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Pearu Peterson +.SH LICENSE +LGPL (see http://www.fsf.org) +.SH VERSION +2.45.241 diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py new file mode 100755 index 000000000..6230590d1 --- /dev/null +++ b/numpy/f2py/f2py2e.py @@ -0,0 +1,555 @@ +#!/usr/bin/env python +""" + +f2py2e - Fortran to Python C/API generator. 2nd Edition. + See __usage__ below. + +Copyright 1999--2005 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. +$Date: 2005/05/06 08:31:19 $ +Pearu Peterson +""" +__version__ = "$Revision: 1.90 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +import sys,os,string,pprint,shutil,types,re +errmess=sys.stderr.write +#outmess=sys.stdout.write +show=pprint.pprint + +import crackfortran +import rules +import cb_rules +import common_rules +import auxfuncs +import cfuncs +import capi_maps +import func2subr +import f90mod_rules + +outmess = auxfuncs.outmess + +try: + from scipy import __core_version__ as scipy_core_version +except ImportError: + scipy_distutils_version = 'N/A' + +__usage__ = """\ +Usage: + +1) To construct extension module sources: + + f2py [<options>] <fortran files> [[[only:]||[skip:]] \\ + <fortran functions> ] \\ + [: <fortran files> ...] + +2) To compile fortran files and build extension modules: + + f2py -c [<options>, <build_flib options>, <extra options>] <fortran files> + +3) To generate signature files: + + f2py -h <filename.pyf> ...< same options as in (1) > + +Description: This program generates a Python C/API file (<modulename>module.c) + that contains wrappers for given fortran functions so that they + can be called from Python. With the -c option the corresponding + extension modules are built. + +Options: + + -h <filename> Write signatures of the fortran routines to file <filename> + and exit. You can then edit <filename> and use it instead + of <fortran files>. If <filename>==stdout then the + signatures are printed to stdout. + <fortran functions> Names of fortran routines for which Python C/API + functions will be generated. Default is all that are found + in <fortran files>. + <fortran files> Paths to fortran/signature files that will be scanned for + <fortran functions> in order to determine their signatures. + skip: Ignore fortran functions that follow until `:'. + only: Use only fortran functions that follow until `:'. + : Get back to <fortran files> mode. + + -m <modulename> Name of the module; f2py generates a Python/C API + file <modulename>module.c or extension module <modulename>. + Default is 'untitled'. + + --[no-]lower Do [not] lower the cases in <fortran files>. By default, + --lower is assumed with -h key, and --no-lower without -h key. + + --build-dir <dirname> All f2py generated files are created in <dirname>. + Default is tempfile.mktemp(). + + --overwrite-signature Overwrite existing signature file. + + --[no-]latex-doc Create (or not) <modulename>module.tex. + Default is --no-latex-doc. + --short-latex Create 'incomplete' LaTeX document (without commands + \\documentclass, \\tableofcontents, and \\begin{document}, + \\end{document}). + + --[no-]rest-doc Create (or not) <modulename>module.rst. + Default is --no-rest-doc. + + --debug-capi Create C/API code that reports the state of the wrappers + during runtime. Useful for debugging. + + --[no-]wrap-functions Create Fortran subroutine wrappers to Fortran 77 + functions. --wrap-functions is default because it ensures + maximum portability/compiler independence. + + --include_paths <path1>:<path2>:... Search include files from the given + directories. + + --help-link [..] List system resources found by system_info.py. See also + --link-<resource> switch below. [..] is optional list + of resources names. E.g. try 'f2py --help-link lapack_opt'. + + --quiet Run quietly. + --verbose Run with extra verbosity. + -v Print f2py version ID and exit. + + +scipy.distutils options (only effective with -c): + + --fcompiler= Specify Fortran compiler type by vendor + --compiler= Specify C compiler type (as defined by distutils) + + --help-fcompiler List available Fortran compilers and exit + --f77exec= Specify the path to F77 compiler + --f90exec= Specify the path to F90 compiler + --f77flags= Specify F77 compiler flags + --f90flags= Specify F90 compiler flags + --opt= Specify optimization flags + --arch= Specify architecture specific optimization flags + --noopt Compile without optimization + --noarch Compile without arch-dependent optimization + --debug Compile with debugging information + +Extra options (only effective with -c): + + --link-<resource> Link extension module with <resource> as defined + by scipy.distutils/system_info.py. E.g. to link + with optimized LAPACK libraries (vecLib on MacOSX, + ATLAS elsewhere), use --link-lapack_opt. + See also --help-link switch. + + -L/path/to/lib/ -l<libname> + -D<define> -U<name> + -I/path/to/include/ + <filename>.o <filename>.so <filename>.a + + Using the following macros may be required with non-gcc Fortran + compilers: + -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN + -DUNDERSCORE_G77 + + When using -DF2PY_REPORT_ATEXIT, a performance report of F2PY + interface is printed out at exit (platforms: Linux). + + When using -DF2PY_REPORT_ON_ARRAY_COPY=<int>, a message is + sent to stderr whenever F2PY interface makes a copy of an + array. Integer <int> sets the threshold for array sizes when + a message should be shown. + +Version: %s +scipy_core Version: %s +Requires: Python 2.3 or higher. +License: LGPL (see http://www.fsf.org) +Copyright 1999 - 2005 Pearu Peterson all rights reserved. +http://cens.ioc.ee/projects/f2py2e/"""%(f2py_version, scipy_core_version) + + +def scaninputline(inputline): + files,funcs,skipfuncs,onlyfuncs,debug=[],[],[],[],[] + f,f2,f3,f4,f5,f6,f7=1,0,0,0,0,0,0 + verbose = 1 + dolc=-1 + dolatexdoc = 0 + dorestdoc = 0 + wrapfuncs = 1 + buildpath = '.' + include_paths = [] + signsfile,modulename=None,None + options = {'buildpath':buildpath} + for l in inputline: + if l=='': pass + elif l=='only:': f=0 + elif l=='skip:': f=-1 + elif l==':': f=1;f4=0 + elif l[:8]=='--debug-': debug.append(l[8:]) + elif l=='--lower': dolc=1 + elif l=='--build-dir': f6=1 + elif l=='--no-lower': dolc=0 + elif l=='--quiet': verbose = 0 + elif l=='--verbose': verbose += 1 + elif l=='--latex-doc': dolatexdoc=1 + elif l=='--no-latex-doc': dolatexdoc=0 + elif l=='--rest-doc': dorestdoc=1 + elif l=='--no-rest-doc': dorestdoc=0 + elif l=='--wrap-functions': wrapfuncs=1 + elif l=='--no-wrap-functions': wrapfuncs=0 + elif l=='--short-latex': options['shortlatex']=1 + elif l=='--overwrite-signature': options['h-overwrite']=1 + elif l=='-h': f2=1 + elif l=='-m': f3=1 + elif l[:2]=='-v': + print f2py_version + sys.exit() + elif l=='--show-compilers': + f5=1 + elif l[:8]=='-include': + cfuncs.outneeds['userincludes'].append(l[9:-1]) + cfuncs.userincludes[l[9:-1]]='#include '+l[8:] + elif l[:15]=='--include_paths': + f7=1 + elif l[0]=='-': + errmess('Unknown option %s\n'%`l`) + sys.exit() + elif f2: f2=0;signsfile=l + elif f3: f3=0;modulename=l + elif f6: f6=0;buildpath=l + elif f7: f7=0;include_paths.extend(l.split(os.pathsep)) + elif f==1: + try: + open(l).close() + files.append(l) + except IOError,detail: + errmess('IOError: %s. Skipping file "%s".\n'%(str(detail),l)) + elif f==-1: skipfuncs.append(l) + elif f==0: onlyfuncs.append(l) + if not f5 and not files and not modulename: + print __usage__ + sys.exit() + if not os.path.isdir(buildpath): + if not verbose: + outmess('Creating build directory %s'%(buildpath)) + os.mkdir(buildpath) + if signsfile: + signsfile = os.path.join(buildpath,signsfile) + if signsfile and os.path.isfile(signsfile) and not options.has_key('h-overwrite'): + errmess('Signature file "%s" exists!!! Use --overwrite-signature to overwrite.\n'%(signsfile)) + sys.exit() + + options['debug']=debug + options['verbose']=verbose + if dolc==-1 and not signsfile: options['do-lower']=0 + else: options['do-lower']=dolc + if modulename: options['module']=modulename + if signsfile: options['signsfile']=signsfile + if onlyfuncs: options['onlyfuncs']=onlyfuncs + if skipfuncs: options['skipfuncs']=skipfuncs + options['dolatexdoc'] = dolatexdoc + options['dorestdoc'] = dorestdoc + options['wrapfuncs'] = wrapfuncs + options['buildpath']=buildpath + options['include_paths']=include_paths + return files,options + +def callcrackfortran(files,options): + rules.options=options + funcs=[] + crackfortran.debug=options['debug'] + crackfortran.verbose=options['verbose'] + if options.has_key('module'): + crackfortran.f77modulename=options['module'] + if options.has_key('skipfuncs'): + crackfortran.skipfuncs=options['skipfuncs'] + if options.has_key('onlyfuncs'): + crackfortran.onlyfuncs=options['onlyfuncs'] + crackfortran.include_paths[:]=options['include_paths'] + crackfortran.dolowercase=options['do-lower'] + postlist=crackfortran.crackfortran(files) + if options.has_key('signsfile'): + outmess('Saving signatures to file "%s"\n'%(options['signsfile'])) + pyf=crackfortran.crack2fortran(postlist) + if options['signsfile'][-6:]=='stdout': + sys.stdout.write(pyf) + else: + f=open(options['signsfile'],'w') + f.write(pyf) + f.close() + return postlist + +def buildmodules(list): + cfuncs.buildcfuncs() + outmess('Building modules...\n') + modules,mnames,isusedby=[],[],{} + for i in range(len(list)): + if string.find(list[i]['name'],'__user__')>=0: + cb_rules.buildcallbacks(list[i]) + else: + if list[i].has_key('use'): + for u in list[i]['use'].keys(): + if not isusedby.has_key(u): isusedby[u]=[] + isusedby[u].append(list[i]['name']) + modules.append(list[i]) + mnames.append(list[i]['name']) + ret = {} + for i in range(len(mnames)): + if isusedby.has_key(mnames[i]): + outmess('\tSkipping module "%s" which is used by %s.\n'%(mnames[i],string.join(map(lambda s:'"%s"'%s,isusedby[mnames[i]]),','))) + else: + um=[] + if modules[i].has_key('use'): + for u in modules[i]['use'].keys(): + if isusedby.has_key(u) and u in mnames: + um.append(modules[mnames.index(u)]) + else: + outmess('\tModule "%s" uses nonexisting "%s" which will be ignored.\n'%(mnames[i],u)) + ret[mnames[i]] = {} + dict_append(ret[mnames[i]],rules.buildmodule(modules[i],um)) + return ret + +def dict_append(d_out,d_in): + for (k,v) in d_in.items(): + if not d_out.has_key(k): + d_out[k] = [] + if type(v) is types.ListType: + d_out[k] = d_out[k] + v + else: + d_out[k].append(v) + +def run_main(comline_list): + """Run f2py as if string.join(comline_list,' ') is used as a command line. + In case of using -h flag, return None. + """ + reload(crackfortran) + f2pydir=os.path.dirname(os.path.abspath(cfuncs.__file__)) + fobjhsrc = os.path.join(f2pydir,'src','fortranobject.h') + fobjcsrc = os.path.join(f2pydir,'src','fortranobject.c') + files,options=scaninputline(comline_list) + auxfuncs.options=options + postlist=callcrackfortran(files,options) + isusedby={} + for i in range(len(postlist)): + if postlist[i].has_key('use'): + for u in postlist[i]['use'].keys(): + if not isusedby.has_key(u): isusedby[u]=[] + isusedby[u].append(postlist[i]['name']) + for i in range(len(postlist)): + if postlist[i]['block']=='python module' and string.find(postlist[i]['name'],'__user__')<0: + if isusedby.has_key(postlist[i]['name']): + #if not quiet: + outmess('Skipping Makefile build for module "%s" which is used by %s\n'%(postlist[i]['name'],string.join(map(lambda s:'"%s"'%s,isusedby[postlist[i]['name']]),','))) + if options.has_key('signsfile'): + if options['verbose']>1: + outmess('Stopping. Edit the signature file and then run f2py on the signature file: ') + outmess('%s %s\n'%(os.path.basename(sys.argv[0]),options['signsfile'])) + return + for i in range(len(postlist)): + if postlist[i]['block']!='python module': + if not options.has_key('python module'): + errmess('Tip: If your original code is Fortran 77 then you must use -m option.\n') + raise TypeError,'All blocks must be module blocks but got %s'%(`postlist[i]['block']`) + auxfuncs.debugoptions=options['debug'] + f90mod_rules.options=options + auxfuncs.wrapfuncs=options['wrapfuncs'] + + ret=buildmodules(postlist) + + for mn in ret.keys(): + dict_append(ret[mn],{'csrc':fobjcsrc,'h':fobjhsrc}) + return ret + +def filter_files(prefix,suffix,files,remove_prefix=None): + """ + Filter files by prefix and suffix. + """ + filtered,rest = [],[] + match = re.compile(prefix+r'.*'+suffix+r'\Z').match + if remove_prefix: + ind = len(prefix) + else: + ind = 0 + for file in map(string.strip,files): + if match(file): filtered.append(file[ind:]) + else: rest.append(file) + return filtered,rest + +def get_prefix(module): + p = os.path.dirname(os.path.dirname(module.__file__)) + return p + +def run_compile(): + """ + Do it all in one call! + """ + import tempfile,os,shutil + + i = sys.argv.index('-c') + del sys.argv[i] + + remove_build_dir = 0 + try: i = sys.argv.index('--build-dir') + except ValueError: i=None + if i is not None: + build_dir = sys.argv[i+1] + del sys.argv[i+1] + del sys.argv[i] + else: + remove_build_dir = 1 + build_dir = os.path.join(tempfile.mktemp()) + + sysinfo_flags = filter(re.compile(r'[-][-]link[-]').match,sys.argv[1:]) + sys.argv = filter(lambda a,flags=sysinfo_flags:a not in flags,sys.argv) + if sysinfo_flags: + sysinfo_flags = [f[7:] for f in sysinfo_flags] + + f2py_flags = filter(re.compile(r'[-][-]((no[-]|)(wrap[-]functions|lower)|debug[-]capi|quiet)|[-]include').match,sys.argv[1:]) + sys.argv = filter(lambda a,flags=f2py_flags:a not in flags,sys.argv) + f2py_flags2 = [] + fl = 0 + for a in sys.argv[1:]: + if a in ['only:','skip:']: + fl = 1 + elif a==':': + fl = 0 + if fl or a==':': + f2py_flags2.append(a) + if f2py_flags2 and f2py_flags2[-1]!=':': + f2py_flags2.append(':') + f2py_flags.extend(f2py_flags2) + + sys.argv = filter(lambda a,flags=f2py_flags2:a not in flags,sys.argv) + + flib_flags = filter(re.compile(r'[-][-]((f(90)?compiler([-]exec|)|compiler)=|help[-]compiler)').match,sys.argv[1:]) + sys.argv = filter(lambda a,flags=flib_flags:a not in flags,sys.argv) + fc_flags = filter(re.compile(r'[-][-]((f(77|90)(flags|exec)|opt|arch)=|(debug|noopt|noarch|help[-]fcompiler))').match,sys.argv[1:]) + sys.argv = filter(lambda a,flags=fc_flags:a not in flags,sys.argv) + + if 1: + del_list = [] + for s in flib_flags: + v = '--fcompiler=' + if s[:len(v)]==v: + from scipy.distutils import fcompiler + allowed_keys = fcompiler.fcompiler_class.keys() + nv = ov = s[len(v):].lower() + if ov not in allowed_keys: + vmap = {} # XXX + try: + nv = vmap[ov] + except KeyError: + if ov not in vmap.values(): + print 'Unknown vendor: "%s"' % (s[len(v):]) + nv = ov + i = flib_flags.index(s) + flib_flags[i] = '--fcompiler=' + nv + continue + for s in del_list: + i = flib_flags.index(s) + del flib_flags[i] + assert len(flib_flags)<=2,`flib_flags` + setup_flags = filter(re.compile(r'[-][-](verbose)').match,sys.argv[1:]) + sys.argv = filter(lambda a,flags=setup_flags:a not in flags,sys.argv) + if '--quiet' in f2py_flags: + setup_flags.append('--quiet') + + modulename = 'untitled' + sources = sys.argv[1:] + if '-m' in sys.argv: + i = sys.argv.index('-m') + modulename = sys.argv[i+1] + del sys.argv[i+1],sys.argv[i] + sources = sys.argv[1:] + else: + from scipy.distutils.command.build_src import get_f2py_modulename + pyf_files,sources = filter_files('','[.]pyf([.]src|)',sources) + sources = pyf_files + sources + for f in pyf_files: + modulename = get_f2py_modulename(f) + if modulename: + break + + extra_objects, sources = filter_files('','[.](o|a|so)',sources) + include_dirs, sources = filter_files('-I','',sources,remove_prefix=1) + library_dirs, sources = filter_files('-L','',sources,remove_prefix=1) + libraries, sources = filter_files('-l','',sources,remove_prefix=1) + undef_macros, sources = filter_files('-U','',sources,remove_prefix=1) + define_macros, sources = filter_files('-D','',sources,remove_prefix=1) + using_numarray = 0 + using_numeric = 0 + for i in range(len(define_macros)): + name_value = string.split(define_macros[i],'=',1) + if len(name_value)==1: + name_value.append(None) + if len(name_value)==2: + define_macros[i] = tuple(name_value) + else: + print 'Invalid use of -D:',name_value + + from scipy.distutils.system_info import get_info + + num_include_dir = None + num_info = {} + #import scipy + #n = 'scipy' + #p = get_prefix(scipy) + #from scipy.distutils.misc_util import get_scipy_include_dirs + #num_info = {'include_dirs': get_scipy_include_dirs()} + + if num_info: + include_dirs.extend(num_info.get('include_dirs',[])) + + from scipy.distutils.core import setup,Extension + ext_args = {'name':modulename,'sources':sources, + 'include_dirs': include_dirs, + 'library_dirs': library_dirs, + 'libraries': libraries, + 'define_macros': define_macros, + 'undef_macros': undef_macros, + 'extra_objects': extra_objects, + 'f2py_options': f2py_flags, + } + + if sysinfo_flags: + from scipy.distutils.misc_util import dict_append + for n in sysinfo_flags: + i = get_info(n) + if not i: + outmess('No %s resources found in system'\ + ' (try `f2py --help-link`)\n' % (`n`)) + dict_append(ext_args,**i) + + ext = Extension(**ext_args) + sys.argv = [sys.argv[0]] + setup_flags + sys.argv.extend(['build', + '--build-temp',build_dir, + '--build-base',build_dir, + '--build-platlib','.']) + if fc_flags: + sys.argv.extend(['config_fc']+fc_flags) + if flib_flags: + sys.argv.extend(['build_ext']+flib_flags) + + setup(ext_modules = [ext]) + + if remove_build_dir and os.path.exists(build_dir): + outmess('Removing build directory %s\n'%(build_dir)) + shutil.rmtree(build_dir) + +def main(): + if '--help-link' in sys.argv[1:]: + sys.argv.remove('--help-link') + from scipy.distutils.system_info import show_all + show_all() + return + if '-c' in sys.argv[1:]: + run_compile() + else: + run_main(sys.argv[1:]) + +#if __name__ == "__main__": +# main() + + +# EOF + diff --git a/numpy/f2py/f2py_testing.py b/numpy/f2py/f2py_testing.py new file mode 100644 index 000000000..1126c3085 --- /dev/null +++ b/numpy/f2py/f2py_testing.py @@ -0,0 +1,74 @@ + +import os,sys,re,time + +def cmdline(): + m=re.compile(r'\A\d+\Z') + args = [] + repeat = 1 + for a in sys.argv[1:]: + if m.match(a): + repeat = eval(a) + else: + args.append(a) + f2py_opts = ' '.join(args) + return repeat,f2py_opts + +if sys.platform[:5]=='linux': + def jiffies(_proc_pid_stat = '/proc/%s/stat'%(os.getpid()), + _load_time=time.time()): + """ Return number of jiffies (1/100ths of a second) that this + process has been scheduled in user mode. See man 5 proc. """ + try: + f=open(_proc_pid_stat,'r') + l = f.readline().split(' ') + f.close() + return int(l[13]) + except: + return int(100*(time.time()-_load_time)) + + def memusage(_proc_pid_stat = '/proc/%s/stat'%(os.getpid())): + """ Return virtual memory size in bytes of the running python. + """ + try: + f=open(_proc_pid_stat,'r') + l = f.readline().split(' ') + f.close() + return int(l[22]) + except: + return +else: + def jiffies(_load_time=time.time()): + """ Return number of jiffies (1/100ths of a second) that this + process has been scheduled in user mode. [Emulation with time.time]. """ + return int(100*(time.time()-_load_time)) + + def memusage(): + pass + +def run(runtest,test_functions,repeat=1): + l = [(t,repr(t.__doc__.split('\n')[1].strip())) for t in test_functions] + #l = [(t,'') for t in test_functions] + start_memusage = memusage() + diff_memusage = None + start_jiffies = jiffies() + i = 0 + while i<repeat: + i += 1 + for t,fname in l: + runtest(t) + if start_memusage is None: continue + if diff_memusage is None: + diff_memusage = memusage() - start_memusage + else: + diff_memusage2 = memusage() - start_memusage + if diff_memusage2!=diff_memusage: + print 'memory usage change at step %i:' % i,\ + diff_memusage2-diff_memusage,\ + fname + diff_memusage = diff_memusage2 + current_memusage = memusage() + print 'run',repeat*len(test_functions),'tests',\ + 'in %.2f seconds' % ((jiffies()-start_jiffies)/100.0) + if start_memusage: + print 'initial virtual memory size:',start_memusage,'bytes' + print 'current virtual memory size:',current_memusage,'bytes' diff --git a/numpy/f2py/f90mod_rules.py b/numpy/f2py/f90mod_rules.py new file mode 100644 index 000000000..9c0d54900 --- /dev/null +++ b/numpy/f2py/f90mod_rules.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python +""" + +Build F90 module support for f2py2e. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/02/03 19:30:23 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.27 $"[10:-1] + +f2py_version='See `f2py -v`' + +import pprint +import sys,string,time,types,copy +errmess=sys.stderr.write +outmess=sys.stdout.write +show=pprint.pprint + +from auxfuncs import * +import capi_maps +import cfuncs +import rules +import func2subr +from crackfortran import undo_rmbadname, undo_rmbadname1 + +options={} + +def findf90modules(m): + if ismodule(m): return [m] + if not hasbody(m): return [] + ret = [] + for b in m['body']: + if ismodule(b): ret.append(b) + else: ret=ret+findf90modules(b) + return ret + +fgetdims1 = """\ + external f2pysetdata + logical ns + integer s(*),r,i,j + ns = .FALSE. + if (allocated(d)) then + do i=1,r + if ((size(d,i).ne.s(i)).and.(s(i).ge.0)) then + ns = .TRUE. + end if + end do + if (ns) then + deallocate(d) + end if + end if + if ((.not.allocated(d)).and.(s(1).ge.1)) then""" + +fgetdims2="""\ + end if + if (allocated(d)) then + do i=1,r + s(i) = size(d,i) + end do + end if + flag = 1 + call f2pysetdata(d,allocated(d))""" + +fgetdims2_sa="""\ + end if + if (allocated(d)) then + do i=1,r + s(i) = size(d,i) + end do + !s(r) must be equal to len(d(1)) + end if + flag = 2 + call f2pysetdata(d,allocated(d))""" + + +def buildhooks(pymod): + global fgetdims1,fgetdims2 + ret = {'f90modhooks':[],'initf90modhooks':[],'body':[], + 'need':['F_FUNC','arrayobject.h'], + 'separatorsfor':{'includes0':'\n','includes':'\n'}, + 'docs':['"Fortran 90/95 modules:\\n"'], + 'latexdoc':[]} + fhooks=[''] + def fadd(line,s=fhooks): s[0] = '%s\n %s'%(s[0],line) + doc = [''] + def dadd(line,s=doc): s[0] = '%s\n%s'%(s[0],line) + for m in findf90modules(pymod): + sargs,fargs,efargs,modobjs,notvars,onlyvars=[],[],[],[],[m['name']],[] + sargsp = [] + ifargs = [] + mfargs = [] + if hasbody(m): + for b in m['body']: notvars.append(b['name']) + for n in m['vars'].keys(): + var = m['vars'][n] + if (n not in notvars) and (not l_or(isintent_hide,isprivate)(var)): + onlyvars.append(n) + mfargs.append(n) + outmess('\t\tConstructing F90 module support for "%s"...\n'%(m['name'])) + if onlyvars: + outmess('\t\t Variables: %s\n'%(string.join(onlyvars))) + chooks=[''] + def cadd(line,s=chooks): s[0] = '%s\n%s'%(s[0],line) + ihooks=[''] + def iadd(line,s=ihooks): s[0] = '%s\n%s'%(s[0],line) + + vrd=capi_maps.modsign2map(m) + cadd('static FortranDataDef f2py_%s_def[] = {'%(m['name'])) + dadd('\\subsection{Fortran 90/95 module \\texttt{%s}}\n'%(m['name'])) + if hasnote(m): + note = m['note'] + if type(note) is type([]): note=string.join(note,'\n') + dadd(note) + if onlyvars: + dadd('\\begin{description}') + for n in onlyvars: + var = m['vars'][n] + modobjs.append(n) + ct = capi_maps.getctype(var) + at = capi_maps.c2capi_map[ct] + dm = capi_maps.getarrdims(n,var) + dms = string.strip(string.replace(dm['dims'],'*','-1')) + dms = string.strip(string.replace(dms,':','-1')) + if not dms: dms='-1' + use_fgetdims2 = fgetdims2 + if isstringarray(var): + if var.has_key('charselector') and var['charselector'].has_key('len'): + cadd('\t{"%s",%s,{{%s,%s}},%s},'\ + %(undo_rmbadname1(n),dm['rank'],dms,var['charselector']['len'],at)) + use_fgetdims2 = fgetdims2_sa + else: + cadd('\t{"%s",%s,{{%s}},%s},'%(undo_rmbadname1(n),dm['rank'],dms,at)) + else: + cadd('\t{"%s",%s,{{%s}},%s},'%(undo_rmbadname1(n),dm['rank'],dms,at)) + dadd('\\item[]{{}\\verb@%s@{}}'%(capi_maps.getarrdocsign(n,var))) + if hasnote(var): + note = var['note'] + if type(note) is type([]): note=string.join(note,'\n') + dadd('--- %s'%(note)) + if isallocatable(var): + fargs.append('f2py_%s_getdims_%s'%(m['name'],n)) + efargs.append(fargs[-1]) + sargs.append('void (*%s)(int*,int*,void(*)(char*,int*),int*)'%(n)) + sargsp.append('void (*)(int*,int*,void(*)(char*,int*),int*)') + iadd('\tf2py_%s_def[i_f2py++].func = %s;'%(m['name'],n)) + fadd('subroutine %s(r,s,f2pysetdata,flag)'%(fargs[-1])) + fadd('use %s, only: d => %s\n'%(m['name'],undo_rmbadname1(n))) + fadd('integer flag\n') + fhooks[0]=fhooks[0]+fgetdims1 + dms = eval('range(1,%s+1)'%(dm['rank'])) + fadd(' allocate(d(%s))\n'%(string.join(map(lambda i:'s(%s)'%i,dms),','))) + fhooks[0]=fhooks[0]+use_fgetdims2 + fadd('end subroutine %s'%(fargs[-1])) + else: + fargs.append(n) + sargs.append('char *%s'%(n)) + sargsp.append('char*') + iadd('\tf2py_%s_def[i_f2py++].data = %s;'%(m['name'],n)) + if onlyvars: + dadd('\\end{description}') + if hasbody(m): + for b in m['body']: + if not isroutine(b): + print 'Skipping',b['block'],b['name'] + continue + modobjs.append('%s()'%(b['name'])) + b['modulename'] = m['name'] + api,wrap=rules.buildapi(b) + if isfunction(b): + fhooks[0]=fhooks[0]+wrap + fargs.append('f2pywrap_%s_%s'%(m['name'],b['name'])) + #efargs.append(fargs[-1]) + ifargs.append(func2subr.createfuncwrapper(b,signature=1)) + else: + fargs.append(b['name']) + mfargs.append(fargs[-1]) + #if options.has_key('--external-modroutines') and options['--external-modroutines']: + # outmess('\t\t\tapplying --external-modroutines for %s\n'%(b['name'])) + # efargs.append(fargs[-1]) + api['externroutines']=[] + ar=applyrules(api,vrd) + ar['docs']=[] + ar['docshort']=[] + ret=dictappend(ret,ar) + cadd('\t{"%s",-1,{{-1}},0,NULL,(void *)f2py_rout_#modulename#_%s_%s,doc_f2py_rout_#modulename#_%s_%s},'%(b['name'],m['name'],b['name'],m['name'],b['name'])) + sargs.append('char *%s'%(b['name'])) + sargsp.append('char *') + iadd('\tf2py_%s_def[i_f2py++].data = %s;'%(m['name'],b['name'])) + cadd('\t{NULL}\n};\n') + iadd('}') + ihooks[0]='static void f2py_setup_%s(%s) {\n\tint i_f2py=0;%s'%(m['name'],string.join(sargs,','),ihooks[0]) + if '_' in m['name']: + F_FUNC='F_FUNC_US' + else: + F_FUNC='F_FUNC' + iadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void (*)(%s));'\ + %(F_FUNC,m['name'],string.upper(m['name']),string.join(sargsp,','))) + iadd('static void f2py_init_%s(void) {'%(m['name'])) + iadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);'\ + %(F_FUNC,m['name'],string.upper(m['name']),m['name'])) + iadd('}\n') + ret['f90modhooks']=ret['f90modhooks']+chooks+ihooks + ret['initf90modhooks']=['\tPyDict_SetItemString(d, "%s", PyFortranObject_New(f2py_%s_def,f2py_init_%s));'%(m['name'],m['name'],m['name'])]+ret['initf90modhooks'] + fadd('') + fadd('subroutine f2pyinit%s(f2pysetupfunc)'%(m['name'])) + #fadd('use %s'%(m['name'])) + if mfargs: + for a in undo_rmbadname(mfargs): + fadd('use %s, only : %s'%(m['name'],a)) + if ifargs: + fadd(string.join(['interface']+ifargs)) + fadd('end interface') + fadd('external f2pysetupfunc') + if efargs: + for a in undo_rmbadname(efargs): + fadd('external %s'%(a)) + fadd('call f2pysetupfunc(%s)'%(string.join(undo_rmbadname(fargs),','))) + fadd('end subroutine f2pyinit%s\n'%(m['name'])) + + dadd(string.replace(string.join(ret['latexdoc'],'\n'),r'\subsection{',r'\subsubsection{')) + + ret['latexdoc']=[] + ret['docs'].append('"\t%s --- %s"'%(m['name'], + string.join(undo_rmbadname(modobjs),','))) + + ret['routine_defs']='' + ret['doc']=[] + ret['docshort']=[] + ret['latexdoc']=doc[0] + if len(ret['docs'])<=1: ret['docs']='' + return ret,fhooks[0] + + diff --git a/numpy/f2py/func2subr.py b/numpy/f2py/func2subr.py new file mode 100644 index 000000000..4039c9996 --- /dev/null +++ b/numpy/f2py/func2subr.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python +""" + +Rules for building C/API module with f2py2e. + +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2004/11/26 11:13:06 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.16 $"[10:-1] + +f2py_version='See `f2py -v`' + +import pprint,copy +import sys,string,time,types,copy +errmess=sys.stderr.write +outmess=sys.stdout.write +show=pprint.pprint + +from auxfuncs import * +def var2fixfortran(vars,a,fa=None,f90mode=None): + if fa is None: + fa = a + if not vars.has_key(a): + show(vars) + outmess('var2fixfortran: No definition for argument "%s".\n'%a) + return '' + if not vars[a].has_key('typespec'): + show(vars[a]) + outmess('var2fixfortran: No typespec for argument "%s".\n'%a) + return '' + vardef=vars[a]['typespec'] + if vardef=='type' and vars[a].has_key('typename'): + vardef='%s(%s)'%(vardef,vars[a]['typename']) + selector={} + lk = '' + if vars[a].has_key('kindselector'): + selector=vars[a]['kindselector'] + lk = 'kind' + elif vars[a].has_key('charselector'): + selector=vars[a]['charselector'] + lk = 'len' + if selector.has_key('*'): + if f90mode: + if selector['*'] in ['*',':','(*)']: + vardef='%s(len=*)'%(vardef) + else: + vardef='%s(%s=%s)'%(vardef,lk,selector['*']) + else: + if selector['*'] in ['*',':']: + vardef='%s*(%s)'%(vardef,selector['*']) + else: + vardef='%s*%s'%(vardef,selector['*']) + else: + if selector.has_key('len'): + vardef='%s(len=%s'%(vardef,selector['len']) + if selector.has_key('kind'): + vardef='%s,kind=%s)'%(vardef,selector['kind']) + else: + vardef='%s)'%(vardef) + elif selector.has_key('kind'): + vardef='%s(kind=%s)'%(vardef,selector['kind']) + + vardef='%s %s'%(vardef,fa) + if vars[a].has_key('dimension'): + vardef='%s(%s)'%(vardef,string.join(vars[a]['dimension'],',')) + return vardef + +def createfuncwrapper(rout,signature=0): + assert isfunction(rout) + ret = [''] + def add(line,ret=ret): + ret[0] = '%s\n %s'%(ret[0],line) + name = rout['name'] + fortranname = getfortranname(rout) + f90mode = ismoduleroutine(rout) + newname = '%sf2pywrap'%(name) + vars = rout['vars'] + if not vars.has_key(newname): + vars[newname] = vars[name] + args = [newname]+rout['args'][1:] + else: + args = [newname]+rout['args'] + + l = var2fixfortran(vars,name,newname,f90mode) + return_char_star = 0 + if l[:13]=='character*(*)': + return_char_star = 1 + if f90mode: l = 'character(len=10)'+l[13:] + else: l = 'character*10'+l[13:] + charselect = vars[name]['charselector'] + if charselect.get('*','')=='(*)': + charselect['*'] = '10' + if f90mode: + sargs = string.join(args,', ') + add('subroutine f2pywrap_%s_%s (%s)'%(rout['modulename'],name,sargs)) + if not signature: + add('use %s, only : %s'%(rout['modulename'],fortranname)) + else: + add('subroutine f2pywrap%s (%s)'%(name,string.join(args,', '))) + add('external %s'%(fortranname)) + #if not return_char_star: + l = l + ', '+fortranname + args = args[1:] + dumped_args = [] + for a in args: + if isexternal(vars[a]): + add('external %s'%(a)) + dumped_args.append(a) + for a in args: + if a in dumped_args: continue + if isscalar(vars[a]): + add(var2fixfortran(vars,a,f90mode=f90mode)) + dumped_args.append(a) + for a in args: + if a in dumped_args: continue + add(var2fixfortran(vars,a,f90mode=f90mode)) + + add(l) + + if not signature: + if islogicalfunction(rout): + add('%s = .not.(.not.%s(%s))'%(newname,fortranname,string.join(args,', '))) + else: + add('%s = %s(%s)'%(newname,fortranname,string.join(args,', '))) + if f90mode: + add('end subroutine f2pywrap_%s_%s'%(rout['modulename'],name)) + else: + add('end') + #print '**'*10 + #print ret[0] + #print '**'*10 + return ret[0] + +def assubr(rout): + if not isfunction_wrap(rout): return rout,'' + fortranname = getfortranname(rout) + name = rout['name'] + outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n'%(name,fortranname)) + rout = copy.copy(rout) + fname = name + rname = fname + if rout.has_key('result'): + rname = rout['result'] + rout['vars'][fname]=rout['vars'][rname] + fvar = rout['vars'][fname] + if not isintent_out(fvar): + if not fvar.has_key('intent'): fvar['intent']=[] + fvar['intent'].append('out') + flag=1 + for i in fvar['intent']: + if i.startswith('out='): + flag = 0 + break + if flag: + fvar['intent'].append('out=%s' % (rname)) + + rout['args'] = [fname] + rout['args'] + return rout,createfuncwrapper(rout) diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py new file mode 100644 index 000000000..cb2d78e65 --- /dev/null +++ b/numpy/f2py/rules.py @@ -0,0 +1,1345 @@ +#!/usr/bin/env python +""" + +Rules for building C/API module with f2py2e. + +Here is a skeleton of a new wrapper function (13Dec2001): + +wrapper_function(args) + declarations + get_python_arguments, say, `a' and `b' + + get_a_from_python + if (successful) { + + get_b_from_python + if (successful) { + + callfortran + if (succesful) { + + put_a_to_python + if (succesful) { + + put_b_to_python + if (succesful) { + + buildvalue = ... + + } + + } + + } + + } + cleanup_b + + } + cleanup_a + + return buildvalue +""" +""" +Copyright 1999,2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2005/08/30 08:58:42 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.129 $"[10:-1] + +import __version__ +f2py_version = __version__.version + +import pprint +import sys,string,time,types,copy +errmess=sys.stderr.write +outmess=sys.stdout.write +show=pprint.pprint + +from auxfuncs import * +import capi_maps +from capi_maps import * +import cfuncs +import common_rules +import use_rules +import f90mod_rules +import func2subr +options={} + +sepdict={} +#for k in ['need_cfuncs']: sepdict[k]=',' +for k in ['decl', + 'frompyobj', + 'cleanupfrompyobj', + 'topyarr','method', + 'pyobjfrom','closepyobjfrom', + 'freemem', + 'userincludes', + 'includes0','includes','typedefs','typedefs_generated', + 'cppmacros','cfuncs','callbacks', + 'latexdoc', + 'restdoc', + 'routine_defs','externroutines', + 'initf2pywraphooks', + 'commonhooks','initcommonhooks', + 'f90modhooks','initf90modhooks']: + sepdict[k]='\n' + +#################### Rules for C/API module ################# + +module_rules={ + 'modulebody':"""\ +/* File: #modulename#module.c + * This file is auto-generated with f2py (version:#f2py_version#). + * f2py is a Fortran to Python Interface Generator (FPIG), Second Edition, + * written by Pearu Peterson <pearu@cens.ioc.ee>. + * See http://cens.ioc.ee/projects/f2py2e/ + * Generation date: """+time.asctime(time.localtime(time.time()))+""" + * $R"""+"""evision:$ + * $D"""+"""ate:$ + * Do not edit this file directly unless you know what you are doing!!! + */ +#ifdef __cplusplus +extern \"C\" { +#endif + +"""+gentitle("See f2py2e/cfuncs.py: includes")+""" +#includes# +#includes0# + +"""+gentitle("See f2py2e/rules.py: mod_rules['modulebody']")+""" +static PyObject *#modulename#_error; +static PyObject *#modulename#_module; + +"""+gentitle("See f2py2e/cfuncs.py: typedefs")+""" +#typedefs# + +"""+gentitle("See f2py2e/cfuncs.py: typedefs_generated")+""" +#typedefs_generated# + +"""+gentitle("See f2py2e/cfuncs.py: cppmacros")+""" +#cppmacros# + +"""+gentitle("See f2py2e/cfuncs.py: cfuncs")+""" +#cfuncs# + +"""+gentitle("See f2py2e/cfuncs.py: userincludes")+""" +#userincludes# + +"""+gentitle("See f2py2e/capi_rules.py: usercode")+""" +#usercode# + +/* See f2py2e/rules.py */ +#externroutines# + +"""+gentitle("See f2py2e/capi_rules.py: usercode1")+""" +#usercode1# + +"""+gentitle("See f2py2e/cb_rules.py: buildcallback")+""" +#callbacks# + +"""+gentitle("See f2py2e/rules.py: buildapi")+""" +#body# + +"""+gentitle("See f2py2e/f90mod_rules.py: buildhooks")+""" +#f90modhooks# + +"""+gentitle("See f2py2e/rules.py: module_rules['modulebody']")+""" + +"""+gentitle("See f2py2e/common_rules.py: buildhooks")+""" +#commonhooks# + +"""+gentitle("See f2py2e/rules.py")+""" + +static FortranDataDef f2py_routine_defs[] = { +#routine_defs# +\t{NULL} +}; + +static PyMethodDef f2py_module_methods[] = { +#pymethoddef# +\t{NULL,NULL} +}; + +DL_EXPORT(void) init#modulename#(void) { +\tint i; +\tPyObject *m,*d, *s; +\tm = #modulename#_module = Py_InitModule(\"#modulename#\", f2py_module_methods); +\tPyFortran_Type.ob_type = &PyType_Type; +\timport_array(); +\tif (PyErr_Occurred()) +\t\tPy_FatalError(\"can't initialize module #modulename# (failed to import scipy.base)\"); +\td = PyModule_GetDict(m); +\ts = PyString_FromString(\"$R"""+"""evision: $\"); +\tPyDict_SetItemString(d, \"__version__\", s); +\ts = PyString_FromString(\"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\"); +\tPyDict_SetItemString(d, \"__doc__\", s); +\t#modulename#_error = PyErr_NewException (\"#modulename#.error\", NULL, NULL); +\tPy_DECREF(s); +\tfor(i=0;f2py_routine_defs[i].name!=NULL;i++) +\t\tPyDict_SetItemString(d, f2py_routine_defs[i].name,PyFortranObject_NewAsAttr(&f2py_routine_defs[i])); +#initf2pywraphooks# +#initf90modhooks# +#initcommonhooks# +#interface_usercode# +\tif (PyErr_Occurred()) +\t\tPy_FatalError(\"can't initialize module #modulename#\"); + +#ifdef F2PY_REPORT_ATEXIT +\ton_exit(f2py_report_on_exit,(void*)\"#modulename#\"); +#endif + +} +#ifdef __cplusplus +} +#endif +""", + 'separatorsfor':{'latexdoc':'\n\n', + 'restdoc':'\n\n'}, + 'latexdoc':['\\section{Module \\texttt{#texmodulename#}}\n', + '#modnote#\n', + '#latexdoc#'], + 'restdoc':['Module #modulename#\n'+'='*80, + '\n#restdoc#'] + } + +defmod_rules=[ + {'body':'/*eof body*/', + 'method':'/*eof method*/', + 'externroutines':'/*eof externroutines*/', + 'routine_defs':'/*eof routine_defs*/', + 'initf90modhooks':'/*eof initf90modhooks*/', + 'initf2pywraphooks':'/*eof initf2pywraphooks*/', + 'initcommonhooks':'/*eof initcommonhooks*/', + 'latexdoc':'', + 'restdoc':'', + 'modnote':{hasnote:'#note#',l_not(hasnote):''}, + } + ] + +routine_rules={ + 'separatorsfor':sepdict, + 'body':""" +#begintitle# +static char doc_#apiname#[] = \"\\\nFunction signature:\\n\\\n\t#docreturn##name#(#docsignatureshort#)\\n\\\n#docstrsigns#\"; +/* #declfortranroutine# */ +static PyObject *#apiname#(const PyObject *capi_self, + PyObject *capi_args, + PyObject *capi_keywds, + #functype# (*f2py_func)(#callprotoargument#)) { +\tPyObject * volatile capi_buildvalue = NULL; +\tvolatile int f2py_success = 1; +#decl# +\tstatic char *capi_kwlist[] = {#kwlist##kwlistopt##kwlistxa#NULL}; +#usercode# +#routdebugenter# +#ifdef F2PY_REPORT_ATEXIT +f2py_start_clock(); +#endif +\tif (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\ +\t\t\"#argformat#|#keyformat##xaformat#:#pyname#\",\\ +\t\tcapi_kwlist#args_capi##keys_capi##keys_xa#))\n\t\treturn NULL; +#frompyobj# +/*end of frompyobj*/ +#ifdef F2PY_REPORT_ATEXIT +f2py_start_call_clock(); +#endif +#callfortranroutine# +if (PyErr_Occurred()) + f2py_success = 0; +#ifdef F2PY_REPORT_ATEXIT +f2py_stop_call_clock(); +#endif +/*end of callfortranroutine*/ +\t\tif (f2py_success) { +#pyobjfrom# +/*end of pyobjfrom*/ +\t\tCFUNCSMESS(\"Building return value.\\n\"); +\t\tcapi_buildvalue = Py_BuildValue(\"#returnformat#\"#return#); +/*closepyobjfrom*/ +#closepyobjfrom# +\t\t} /*if (f2py_success) after callfortranroutine*/ +/*cleanupfrompyobj*/ +#cleanupfrompyobj# +\tif (capi_buildvalue == NULL) { +#routdebugfailure# +\t} else { +#routdebugleave# +\t} +\tCFUNCSMESS(\"Freeing memory.\\n\"); +#freemem# +#ifdef F2PY_REPORT_ATEXIT +f2py_stop_clock(); +#endif +\treturn capi_buildvalue; +} +#endtitle# +""", + 'routine_defs':'#routine_def#', + 'initf2pywraphooks':'#initf2pywraphook#', + 'externroutines':'#declfortranroutine#', + 'doc':'#docreturn##name#(#docsignature#)', + 'docshort':'#docreturn##name#(#docsignatureshort#)', + 'docs':'"\t#docreturn##name#(#docsignature#)\\n"\n', + 'need':['arrayobject.h','CFUNCSMESS','MINMAX'], + 'cppmacros':{debugcapi:'#define DEBUGCFUNCS'}, + 'latexdoc':['\\subsection{Wrapper function \\texttt{#texname#}}\n', + """ +\\noindent{{}\\verb@#docreturn##name#@{}}\\texttt{(#latexdocsignatureshort#)} +#routnote# + +#latexdocstrsigns# +"""], + 'restdoc':['Wrapped function ``#name#``\n'+'-'*80, + + ] + } + +################## Rules for C/API function ############## + +rout_rules=[ + { # Init + 'separatorsfor': {'callfortranroutine':'\n','routdebugenter':'\n','decl':'\n', + 'routdebugleave':'\n','routdebugfailure':'\n', + 'setjmpbuf':' || ', + 'docstrreq':'\n','docstropt':'\n','docstrout':'\n', + 'docstrcbs':'\n','docstrsigns':'\\n"\n"', + 'latexdocstrsigns':'\n', + 'latexdocstrreq':'\n','latexdocstropt':'\n', + 'latexdocstrout':'\n','latexdocstrcbs':'\n', + }, + 'kwlist':'','kwlistopt':'','callfortran':'','callfortranappend':'', + 'docsign':'','docsignopt':'','decl':'/*decl*/', + 'freemem':'/*freemem*/', + 'docsignshort':'','docsignoptshort':'', + 'docstrsigns':'','latexdocstrsigns':'', + 'docstrreq':'Required arguments:', + 'docstropt':'Optional arguments:', + 'docstrout':'Return objects:', + 'docstrcbs':'Call-back functions:', + 'latexdocstrreq':'\\noindent Required arguments:', + 'latexdocstropt':'\\noindent Optional arguments:', + 'latexdocstrout':'\\noindent Return objects:', + 'latexdocstrcbs':'\\noindent Call-back functions:', + 'args_capi':'','keys_capi':'','functype':'', + 'frompyobj':'/*frompyobj*/', + 'cleanupfrompyobj':['/*end of cleanupfrompyobj*/'], #this list will be reversed + 'pyobjfrom':'/*pyobjfrom*/', + 'closepyobjfrom':['/*end of closepyobjfrom*/'], #this list will be reversed + 'topyarr':'/*topyarr*/','routdebugleave':'/*routdebugleave*/', + 'routdebugenter':'/*routdebugenter*/', + 'routdebugfailure':'/*routdebugfailure*/', + 'callfortranroutine':'/*callfortranroutine*/', + 'argformat':'','keyformat':'','need_cfuncs':'', + 'docreturn':'','return':'','returnformat':'','rformat':'', + 'kwlistxa':'','keys_xa':'','xaformat':'','docsignxa':'','docsignxashort':'', + 'initf2pywraphook':'', + 'routnote':{hasnote:'--- #note#',l_not(hasnote):''}, + },{ + 'apiname':'f2py_rout_#modulename#_#name#', + 'pyname':'#modulename#.#name#', + 'decl':'', + '_check':l_not(ismoduleroutine) + },{ + 'apiname':'f2py_rout_#modulename#_#f90modulename#_#name#', + 'pyname':'#modulename#.#f90modulename#.#name#', + 'decl':'', + '_check':ismoduleroutine + },{ # Subroutine + 'functype':'void', + 'declfortranroutine':{l_and(l_not(l_or(ismoduleroutine,isintent_c)),l_not(isdummyroutine)):'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);', + l_and(l_not(ismoduleroutine),isintent_c,l_not(isdummyroutine)):'extern void #fortranname#(#callprotoargument#);', + ismoduleroutine:'', + isdummyroutine:'' + }, + 'routine_def':{l_not(l_or(ismoduleroutine,isintent_c,isdummyroutine)):'\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine),isintent_c,l_not(isdummyroutine)):'\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine),isdummyroutine):'\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'need':{l_and(l_not(l_or(ismoduleroutine,isintent_c)),l_not(isdummyroutine)):'F_FUNC'}, + 'callfortranroutine':[ + {debugcapi:["""\tfprintf(stderr,\"debug-capi:Fortran subroutine `#fortranname#(#callfortran#)\'\\n\");"""]}, + {hasexternals:"""\ +\t\tif (#setjmpbuf#) { +\t\t\tf2py_success = 0; +\t\t} else {"""}, + {isthreadsafe:'\t\t\tPy_BEGIN_ALLOW_THREADS'}, + {hascallstatement:'''\t\t\t\t#callstatement#; +\t\t\t\t/*(*f2py_func)(#callfortran#);*/'''}, + {l_not(l_or(hascallstatement,isdummyroutine)):'\t\t\t\t(*f2py_func)(#callfortran#);'}, + {isthreadsafe:'\t\t\tPy_END_ALLOW_THREADS'}, + {hasexternals:"""\t\t}"""} + ], + '_check':issubroutine, + },{ # Wrapped function + 'functype':'void', + 'declfortranroutine':{l_not(l_or(ismoduleroutine,isdummyroutine)):'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);', + isdummyroutine:'', + }, + + 'routine_def':{l_not(l_or(ismoduleroutine,isdummyroutine)):'\t{\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + isdummyroutine:'\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'initf2pywraphook':{l_not(l_or(ismoduleroutine,isdummyroutine)):''' + { + extern #ctype# #F_FUNC#(#name_lower#,#NAME#)(void); + PyObject* o = PyDict_GetItemString(d,"#name#"); + PyObject_SetAttrString(o,"_cpointer", PyCObject_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL)); + } + '''}, + 'need':{l_not(l_or(ismoduleroutine,isdummyroutine)):['F_WRAPPEDFUNC','F_FUNC']}, + 'callfortranroutine':[ + {debugcapi:["""\tfprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]}, + {hasexternals:"""\ +\tif (#setjmpbuf#) { +\t\tf2py_success = 0; +\t} else {"""}, + {isthreadsafe:'\tPy_BEGIN_ALLOW_THREADS'}, + {l_not(l_or(hascallstatement,isdummyroutine)):'\t(*f2py_func)(#callfortran#);'}, + {hascallstatement:'\t#callstatement#;\n\t/*(*f2py_func)(#callfortran#);*/'}, + {isthreadsafe:'\tPy_END_ALLOW_THREADS'}, + {hasexternals:'\t}'} + ], + '_check':isfunction_wrap, + },{ # Function + 'functype':'#ctype#', + 'docreturn':{l_not(isintent_hide):'#rname#,'}, + 'docstrout':'\t#pydocsignout#', + 'latexdocstrout':['\\item[]{{}\\verb@#pydocsignout#@{}}', + {hasresultnote:'--- #resultnote#'}], + 'callfortranroutine':[{l_and(debugcapi,isstringfunction):"""\ +#ifdef USESCOMPAQFORTRAN +\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callcompaqfortran#)\\n\"); +#else +\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\"); +#endif +"""}, + {l_and(debugcapi,l_not(isstringfunction)):"""\ +\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\"); +"""} + ], + '_check':l_and(isfunction,l_not(isfunction_wrap)) + },{ # Scalar function + 'declfortranroutine':{l_and(l_not(l_or(ismoduleroutine,isintent_c)),l_not(isdummyroutine)):'extern #ctype# #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);', + l_and(l_not(ismoduleroutine),isintent_c,l_not(isdummyroutine)):'extern #ctype# #fortranname#(#callprotoargument#);', + isdummyroutine:'' + }, + 'routine_def':{l_and(l_not(l_or(ismoduleroutine,isintent_c)),l_not(isdummyroutine)):'\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine),isintent_c,l_not(isdummyroutine)):'\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},', + isdummyroutine:'\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},', + }, + 'decl':[{iscomplexfunction_warn:'\t#ctype# #name#_return_value={0,0};', + l_not(iscomplexfunction):'\t#ctype# #name#_return_value=0;'}, + {iscomplexfunction:'\tPyObject *#name#_return_value_capi = Py_None;'} + ], + 'callfortranroutine':[ + {hasexternals:"""\ +\tif (#setjmpbuf#) { +\t\tf2py_success = 0; +\t} else {"""}, + {isthreadsafe:'\tPy_BEGIN_ALLOW_THREADS'}, + {hascallstatement:'''\t#callstatement#; +/*\t#name#_return_value = (*f2py_func)(#callfortran#);*/ +'''}, + {l_not(l_or(hascallstatement,isdummyroutine)):'\t#name#_return_value = (*f2py_func)(#callfortran#);'}, + {isthreadsafe:'\tPy_END_ALLOW_THREADS'}, + {hasexternals:'\t}'}, + {l_and(debugcapi,iscomplexfunction):'\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value.r,#name#_return_value.i);'}, + {l_and(debugcapi,l_not(iscomplexfunction)):'\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value);'}], + 'pyobjfrom':{iscomplexfunction:'\t#name#_return_value_capi = pyobj_from_#ctype#1(#name#_return_value);'}, + 'need':[{l_not(isdummyroutine):'F_FUNC'}, + {iscomplexfunction:'pyobj_from_#ctype#1'}, + {islong_longfunction:'long_long'}, + {islong_doublefunction:'long_double'}], + 'returnformat':{l_not(isintent_hide):'#rformat#'}, + 'return':{iscomplexfunction:',#name#_return_value_capi', + l_not(l_or(iscomplexfunction,isintent_hide)):',#name#_return_value'}, + '_check':l_and(isfunction,l_not(isstringfunction),l_not(isfunction_wrap)) + },{ # String function # in use for --no-wrap + 'declfortranroutine':'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);', + 'routine_def':{l_not(l_or(ismoduleroutine,isintent_c)): +# '\t{\"#name#\",-1,{{-1}},0,(char *)F_FUNC(#fortranname#,#FORTRANNAME#),(void *)#apiname#,doc_#apiname#},', + '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},', + l_and(l_not(ismoduleroutine),isintent_c): +# '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(void *)#apiname#,doc_#apiname#},' + '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},' + }, + 'decl':['\t#ctype# #name#_return_value = NULL;', + '\tint #name#_return_value_len = 0;'], + 'callfortran':'#name#_return_value,#name#_return_value_len,', + 'callfortranroutine':['\t#name#_return_value_len = #rlength#;', + '\tif ((#name#_return_value = (string)malloc(sizeof(char)*(#name#_return_value_len+1))) == NULL) {', + '\t\tPyErr_SetString(PyExc_MemoryError, \"out of memory\");', + '\t\tf2py_success = 0;', + '\t} else {', + "\t\t(#name#_return_value)[#name#_return_value_len] = '\\0';", + '\t}', + '\tif (f2py_success) {', + {hasexternals:"""\ +\t\tif (#setjmpbuf#) { +\t\t\tf2py_success = 0; +\t\t} else {"""}, + {isthreadsafe:'\t\tPy_BEGIN_ALLOW_THREADS'}, + """\ +#ifdef USESCOMPAQFORTRAN +\t\t(*f2py_func)(#callcompaqfortran#); +#else +\t\t(*f2py_func)(#callfortran#); +#endif +""", + {isthreadsafe:'\t\tPy_END_ALLOW_THREADS'}, + {hasexternals:'\t\t}'}, + {debugcapi:'\t\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value_len,#name#_return_value);'}, + '\t} /* if (f2py_success) after (string)malloc */', + ], + 'returnformat':'#rformat#', + 'return':',#name#_return_value', + 'freemem':'\tSTRINGFREE(#name#_return_value);', + 'need':['F_FUNC','#ctype#','STRINGFREE'], + '_check':l_and(isstringfunction,l_not(isfunction_wrap)) # ???obsolete + }, + { # Debugging + 'routdebugenter':'\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#(#docsignature#)\\n");', + 'routdebugleave':'\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: successful.\\n");', + 'routdebugfailure':'\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: failure.\\n");', + '_check':debugcapi + } + ] + +################ Rules for arguments ################## + +typedef_need_dict = {islong_long:'long_long', + islong_double:'long_double', + islong_complex:'complex_long_double', + isunsigned_char:'unsigned_char', + isunsigned_short:'unsigned_short', + isunsigned:'unsigned', + isunsigned_long_long:'unsigned_long_long'} + +aux_rules=[ + { + 'separatorsfor':sepdict + }, + { # Common + 'frompyobj':['\t/* Processing auxiliary variable #varname# */', + {debugcapi:'\tfprintf(stderr,"#vardebuginfo#\\n");'},], + 'cleanupfrompyobj':'\t/* End of cleaning variable #varname# */', + 'need':typedef_need_dict, + }, +# Scalars (not complex) + { # Common + 'decl':'\t#ctype# #varname# = 0;', + 'need':{hasinitvalue:'math.h'}, + 'frompyobj':{hasinitvalue:'\t#varname# = #init#;'}, + '_check':l_and(isscalar,l_not(iscomplex)), + }, + { + 'return':',#varname#', + 'docstrout':'\t#pydocsignout#', + 'docreturn':'#outvarname#,', + 'returnformat':'#varrformat#', + '_check':l_and(isscalar,l_not(iscomplex),isintent_out), + }, +# Complex scalars + { # Common + 'decl':'\t#ctype# #varname#;', + 'frompyobj': {hasinitvalue:'\t#varname#.r = #init.r#, #varname#.i = #init.i#;'}, + '_check':iscomplex + }, +# String + { # Common + 'decl':['\t#ctype# #varname# = NULL;', + '\tint slen(#varname#);', + ], + 'need':['len..'], + '_check':isstring + }, +# Array + { # Common + 'decl':['\t#ctype# *#varname# = NULL;', + '\tintp #varname#_Dims[#rank#] = {#rank*[-1]#};', + '\tconst int #varname#_Rank = #rank#;', + ], + 'need':['len..',{hasinitvalue:'forcomb'},{hasinitvalue:'CFUNCSMESS'}], + '_check':isarray + }, +# Scalararray + { # Common + '_check':l_and(isarray,l_not(iscomplexarray)) + },{ # Not hidden + '_check':l_and(isarray,l_not(iscomplexarray),isintent_nothide) + }, +# Integer*1 array + {'need':'#ctype#', + '_check':isint1array, + '_depend':'' + }, +# Integer*-1 array + {'need':'#ctype#', + '_check':isunsigned_chararray, + '_depend':'' + }, +# Integer*-2 array + {'need':'#ctype#', + '_check':isunsigned_shortarray, + '_depend':'' + }, +# Integer*-8 array + {'need':'#ctype#', + '_check':isunsigned_long_longarray, + '_depend':'' + }, +# Complexarray + {'need':'#ctype#', + '_check':iscomplexarray, + '_depend':'' + }, +# Stringarray + { + 'callfortranappend':{isarrayofstrings:'flen(#varname#),'}, + 'need':'string', + '_check':isstringarray + } + ] + +arg_rules=[ + { + 'separatorsfor':sepdict + }, + { # Common + 'frompyobj':['\t/* Processing variable #varname# */', + {debugcapi:'\tfprintf(stderr,"#vardebuginfo#\\n");'},], + 'cleanupfrompyobj':'\t/* End of cleaning variable #varname# */', + '_depend':'', + 'need':typedef_need_dict, + }, +# Doc signatures + { + 'docstropt':{l_and(isoptional,isintent_nothide):'\t#pydocsign#'}, + 'docstrreq':{l_and(isrequired,isintent_nothide):'\t#pydocsign#'}, + 'docstrout':{isintent_out:'\t#pydocsignout#'}, + 'latexdocstropt':{l_and(isoptional,isintent_nothide):['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote:'--- #note#'}]}, + 'latexdocstrreq':{l_and(isrequired,isintent_nothide):['\\item[]{{}\\verb@#pydocsign#@{}}', + {hasnote:'--- #note#'}]}, + 'latexdocstrout':{isintent_out:['\\item[]{{}\\verb@#pydocsignout#@{}}', + {l_and(hasnote,isintent_hide):'--- #note#', + l_and(hasnote,isintent_nothide):'--- See above.'}]}, + 'depend':'' + }, +# Required/Optional arguments + { + 'kwlist':'"#varname#",', + 'docsign':'#varname#,', + '_check':l_and(isintent_nothide,l_not(isoptional)) + }, + { + 'kwlistopt':'"#varname#",', + 'docsignopt':'#varname#=#showinit#,', + 'docsignoptshort':'#varname#,', + '_check':l_and(isintent_nothide,isoptional) + }, +# Docstring/BuildValue + { + 'docreturn':'#outvarname#,', + 'returnformat':'#varrformat#', + '_check':isintent_out + }, +# Externals (call-back functions) + { # Common + 'docsignxa':{isintent_nothide:'#varname#_extra_args=(),'}, + 'docsignxashort':{isintent_nothide:'#varname#_extra_args,'}, + 'docstropt':{isintent_nothide:'\t#varname#_extra_args := () input tuple'}, + 'docstrcbs':'#cbdocstr#', + 'latexdocstrcbs':'\\item[] #cblatexdocstr#', + 'latexdocstropt':{isintent_nothide:'\\item[]{{}\\verb@#varname#_extra_args := () input tuple@{}} --- Extra arguments for call-back function {{}\\verb@#varname#@{}}.'}, + 'decl':['\tPyObject *#varname#_capi = Py_None;', + '\tPyTupleObject *#varname#_xa_capi = NULL;', + '\tPyTupleObject *#varname#_args_capi = NULL;', + '\tint #varname#_nofargs_capi = 0;', + {l_not(isintent_callback):'\t#cbname#_typedef #varname#_cptr;'} + ], + 'kwlistxa':{isintent_nothide:'"#varname#_extra_args",'}, + 'argformat':{isrequired:'O'}, + 'keyformat':{isoptional:'O'}, + 'xaformat':{isintent_nothide:'O!'}, + 'args_capi':{isrequired:',&#varname#_capi'}, + 'keys_capi':{isoptional:',&#varname#_capi'}, + 'keys_xa':',&PyTuple_Type,&#varname#_xa_capi', + 'setjmpbuf':'(setjmp(#cbname#_jmpbuf))', + 'callfortran':{l_not(isintent_callback):'#varname#_cptr,'}, + 'need':['#cbname#','setjmp.h'], + '_check':isexternal + }, + { + 'frompyobj':[{l_not(isintent_callback):"""\ +if(PyCObject_Check(#varname#_capi)) { + #varname#_cptr = PyCObject_AsVoidPtr(#varname#_capi); +} else { + #varname#_cptr = #cbname#; +} +"""},{isintent_callback:"""\ +if (#varname#_capi==Py_None) { + #varname#_capi = PyObject_GetAttrString(#modulename#_module,\"#varname#\"); + if (#varname#_capi) { + if (#varname#_xa_capi==NULL) { + if (PyObject_HasAttrString(#modulename#_module,\"#varname#_extra_args\")) { + PyObject* capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#varname#_extra_args\"); + if (capi_tmp) + #varname#_xa_capi = (PyTupleObject *)PySequence_Tuple(capi_tmp); + else + #varname#_xa_capi = (PyTupleObject *)Py_BuildValue(\"()\"); + if (#varname#_xa_capi==NULL) { + PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#varname#_extra_args to tuple.\\n\"); + return NULL; + } + } + } + } + if (#varname#_capi==NULL) { + PyErr_SetString(#modulename#_error,\"Callback #varname# not defined (as an argument or module #modulename# attribute).\\n\"); + return NULL; + } +} +"""}, +## {l_not(isintent_callback):"""\ +## if (#varname#_capi==Py_None) { +## printf(\"hoi\\n\"); +## } +## """}, +"""\ +\t#varname#_nofargs_capi = #cbname#_nofargs; +\tif (create_cb_arglist(#varname#_capi,#varname#_xa_capi,#maxnofargs#,#nofoptargs#,&#cbname#_nofargs,&#varname#_args_capi,\"failed in processing argument list for call-back #varname#.\")) { +\t\tjmp_buf #varname#_jmpbuf;""", +{debugcapi:["""\ +\t\tfprintf(stderr,\"debug-capi:Assuming %d arguments; at most #maxnofargs#(-#nofoptargs#) is expected.\\n\",#cbname#_nofargs); +\t\tCFUNCSMESSPY(\"for #varname#=\",#cbname#_capi);""", +{l_not(isintent_callback):"""\t\tfprintf(stderr,\"#vardebugshowvalue# (call-back in C).\\n\",#cbname#);"""}]}, + """\ +\t\tCFUNCSMESS(\"Saving jmpbuf for `#varname#`.\\n\"); +\t\tSWAP(#varname#_capi,#cbname#_capi,PyObject); +\t\tSWAP(#varname#_args_capi,#cbname#_args_capi,PyTupleObject); +\t\tmemcpy(&#varname#_jmpbuf,&#cbname#_jmpbuf,sizeof(jmp_buf));""", + ], +'cleanupfrompyobj': +"""\ +\t\tCFUNCSMESS(\"Restoring jmpbuf for `#varname#`.\\n\"); +\t\t#cbname#_capi = #varname#_capi; +\t\tPy_DECREF(#cbname#_args_capi); +\t\t#cbname#_args_capi = #varname#_args_capi; +\t\t#cbname#_nofargs = #varname#_nofargs_capi; +\t\tmemcpy(&#cbname#_jmpbuf,&#varname#_jmpbuf,sizeof(jmp_buf)); +\t}""", + 'need':['SWAP','create_cb_arglist'], + '_check':isexternal, + '_depend':'' + }, +# Scalars (not complex) + { # Common + 'decl':'\t#ctype# #varname# = 0;', + 'pyobjfrom':{debugcapi:'\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'}, + 'callfortran':{isintent_c:'#varname#,',l_not(isintent_c):'&#varname#,'}, + 'return':{isintent_out:',#varname#'}, + '_check':l_and(isscalar,l_not(iscomplex)) + },{ + 'need':{hasinitvalue:'math.h'}, + '_check':l_and(isscalar,l_not(iscomplex)), + #'_depend':'' + },{ # Not hidden + 'decl':'\tPyObject *#varname#_capi = Py_None;', + 'argformat':{isrequired:'O'}, + 'keyformat':{isoptional:'O'}, + 'args_capi':{isrequired:',&#varname#_capi'}, + 'keys_capi':{isoptional:',&#varname#_capi'}, + 'pyobjfrom':{isintent_inout:"""\ +\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#); +\tif (f2py_success) {"""}, + 'closepyobjfrom':{isintent_inout:"\t} /*if (f2py_success) of #varname# pyobjfrom*/"}, + 'need':{isintent_inout:'try_pyarr_from_#ctype#'}, + '_check':l_and(isscalar,l_not(iscomplex),isintent_nothide) + },{ + 'frompyobj':[ +# hasinitvalue... +# if pyobj is None: +# varname = init +# else +# from_pyobj(varname) +# +# isoptional and noinitvalue... +# if pyobj is not None: +# from_pyobj(varname) +# else: +# varname is uninitialized +# +# ... +# from_pyobj(varname) +# + {hasinitvalue:'\tif (#varname#_capi == Py_None) #varname# = #init#; else', + '_depend':''}, + {l_and(isoptional,l_not(hasinitvalue)):'\tif (#varname#_capi != Py_None)', + '_depend':''}, + {l_not(islogical):'''\ +\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#"); +\tif (f2py_success) {'''}, + {islogical:'''\ +\t\t#varname# = (#ctype#)PyObject_IsTrue(#varname#_capi); +\t\tf2py_success = 1; +\tif (f2py_success) {'''}, + ], + 'cleanupfrompyobj':'\t} /*if (f2py_success) of #varname#*/', + 'need':{l_not(islogical):'#ctype#_from_pyobj'}, + '_check':l_and(isscalar,l_not(iscomplex),isintent_nothide), + '_depend':'' +# },{ # Hidden +# '_check':l_and(isscalar,l_not(iscomplex),isintent_hide) + },{ # Hidden + 'frompyobj':{hasinitvalue:'\t#varname# = #init#;'}, + 'need':typedef_need_dict, + '_check':l_and(isscalar,l_not(iscomplex),isintent_hide), + '_depend':'' + },{ # Common + 'frompyobj':{debugcapi:'\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'}, + '_check':l_and(isscalar,l_not(iscomplex)), + '_depend':'' + }, +# Complex scalars + { # Common + 'decl':'\t#ctype# #varname#;', + 'callfortran':{isintent_c:'#varname#,',l_not(isintent_c):'&#varname#,'}, + 'pyobjfrom':{debugcapi:'\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'}, + 'return':{isintent_out:',#varname#_capi'}, + '_check':iscomplex + },{ # Not hidden + 'decl':'\tPyObject *#varname#_capi = Py_None;', + 'argformat':{isrequired:'O'}, + 'keyformat':{isoptional:'O'}, + 'args_capi':{isrequired:',&#varname#_capi'}, + 'keys_capi':{isoptional:',&#varname#_capi'}, + 'need':{isintent_inout:'try_pyarr_from_#ctype#'}, + 'pyobjfrom':{isintent_inout:"""\ +\t\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#); +\t\tif (f2py_success) {"""}, + 'closepyobjfrom':{isintent_inout:"\t\t} /*if (f2py_success) of #varname# pyobjfrom*/"}, + '_check':l_and(iscomplex,isintent_nothide) + },{ + 'frompyobj':[{hasinitvalue:'\tif (#varname#_capi==Py_None) {#varname#.r = #init.r#, #varname#.i = #init.i#;} else'}, + {l_and(isoptional,l_not(hasinitvalue)):'\tif (#varname#_capi != Py_None)'}, +# '\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#ctype#_from_pyobj failed in converting #nth# `#varname#\' of #pyname# to C #ctype#\\n");' + '\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");' + '\n\tif (f2py_success) {'], + 'cleanupfrompyobj':'\t} /*if (f2py_success) of #varname# frompyobj*/', + 'need':['#ctype#_from_pyobj'], + '_check':l_and(iscomplex,isintent_nothide), + '_depend':'' + },{ # Hidden + 'decl':{isintent_out:'\tPyObject *#varname#_capi = Py_None;'}, + '_check':l_and(iscomplex,isintent_hide) + },{ + 'frompyobj': {hasinitvalue:'\t#varname#.r = #init.r#, #varname#.i = #init.i#;'}, + '_check':l_and(iscomplex,isintent_hide), + '_depend':'' + },{ # Common + 'pyobjfrom':{isintent_out:'\t#varname#_capi = pyobj_from_#ctype#1(#varname#);'}, + 'need':['pyobj_from_#ctype#1'], + '_check':iscomplex + },{ + 'frompyobj':{debugcapi:'\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'}, + '_check':iscomplex, + '_depend':'' + }, +# String + { # Common + 'decl':['\t#ctype# #varname# = NULL;', + '\tint slen(#varname#);', + '\tPyObject *#varname#_capi = Py_None;'], + 'callfortran':'#varname#,', + 'callfortranappend':'slen(#varname#),', + 'pyobjfrom':{debugcapi:'\tfprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'}, +# 'freemem':'\tSTRINGFREE(#varname#);', + 'return':{isintent_out:',#varname#'}, + 'need':['len..'],#'STRINGFREE'], + '_check':isstring + },{ # Common + 'frompyobj':"""\ +\tslen(#varname#) = #length#; +\tf2py_success = #ctype#_from_pyobj(&#varname#,&slen(#varname#),#init#,#varname#_capi,\"#ctype#_from_pyobj failed in converting #nth# `#varname#\' of #pyname# to C #ctype#\"); +\tif (f2py_success) {""", + 'cleanupfrompyobj':"""\ +\t\tSTRINGFREE(#varname#); +\t} /*if (f2py_success) of #varname#*/""", + 'need':['#ctype#_from_pyobj','len..','STRINGFREE'], + '_check':isstring, + '_depend':'' + },{ # Not hidden + 'argformat':{isrequired:'O'}, + 'keyformat':{isoptional:'O'}, + 'args_capi':{isrequired:',&#varname#_capi'}, + 'keys_capi':{isoptional:',&#varname#_capi'}, + 'pyobjfrom':{isintent_inout:'''\ +\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,#varname#); +\tif (f2py_success) {'''}, + 'closepyobjfrom':{isintent_inout:'\t} /*if (f2py_success) of #varname# pyobjfrom*/'}, + 'need':{isintent_inout:'try_pyarr_from_#ctype#'}, + '_check':l_and(isstring,isintent_nothide) + },{ # Hidden + '_check':l_and(isstring,isintent_hide) + },{ + 'frompyobj':{debugcapi:'\tfprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'}, + '_check':isstring, + '_depend':'' + }, +# Array + { # Common + 'decl':['\t#ctype# *#varname# = NULL;', + '\tintp #varname#_Dims[#rank#] = {#rank*[-1]#};', + '\tconst int #varname#_Rank = #rank#;', + '\tPyArrayObject *capi_#varname#_tmp = NULL;', + '\tint capi_#varname#_intent = 0;', + ], + 'callfortran':'#varname#,', + 'return':{isintent_out:',capi_#varname#_tmp'}, + 'need':'len..', + '_check':isarray + },{ # intent(overwrite) array + 'decl':'\tint capi_overwrite_#varname# = 1;', + 'kwlistxa':'"overwrite_#varname#",', + 'xaformat':'i', + 'keys_xa':',&capi_overwrite_#varname#', + 'docsignxa':'overwrite_#varname#=1,', + 'docsignxashort':'overwrite_#varname#,', + 'docstropt':'\toverwrite_#varname# := 1 input int', + '_check':l_and(isarray,isintent_overwrite), + },{ + 'frompyobj':'\tcapi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);', + '_check':l_and(isarray,isintent_overwrite), + '_depend':'', + }, + { # intent(copy) array + 'decl':'\tint capi_overwrite_#varname# = 0;', + 'kwlistxa':'"overwrite_#varname#",', + 'xaformat':'i', + 'keys_xa':',&capi_overwrite_#varname#', + 'docsignxa':'overwrite_#varname#=0,', + 'docsignxashort':'overwrite_#varname#,', + 'docstropt':'\toverwrite_#varname# := 0 input int', + '_check':l_and(isarray,isintent_copy), + },{ + 'frompyobj':'\tcapi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);', + '_check':l_and(isarray,isintent_copy), + '_depend':'', + },{ + 'need':[{hasinitvalue:'forcomb'},{hasinitvalue:'CFUNCSMESS'}], + '_check':isarray, + '_depend':'' + },{ # Not hidden + 'decl':'\tPyObject *#varname#_capi = Py_None;', + 'argformat':{isrequired:'O'}, + 'keyformat':{isoptional:'O'}, + 'args_capi':{isrequired:',&#varname#_capi'}, + 'keys_capi':{isoptional:',&#varname#_capi'}, +# 'pyobjfrom':{isintent_inout:"""\ +# /* Partly because of the following hack, intent(inout) is depreciated, +# Use intent(in,out) instead. + +# \tif ((#varname#_capi != Py_None) && PyArray_Check(#varname#_capi) \\ +# \t\t&& (#varname#_capi != (PyObject *)capi_#varname#_tmp)) { +# \t\tif (((PyArrayObject *)#varname#_capi)->nd != capi_#varname#_tmp->nd) { +# \t\t\tif (#varname#_capi != capi_#varname#_tmp->base) +# \t\t\t\tcopy_ND_array((PyArrayObject *)capi_#varname#_tmp->base,(PyArrayObject *)#varname#_capi); +# \t\t} else +# \t\t\tcopy_ND_array(capi_#varname#_tmp,(PyArrayObject *)#varname#_capi); +# \t} +# */ +# """}, +# 'need':{isintent_inout:'copy_ND_array'}, + '_check':l_and(isarray,isintent_nothide) + },{ + 'frompyobj':['\t#setdims#;', + '\tcapi_#varname#_intent |= #intent#;', + {isintent_hide:'\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,Py_None);'}, + {isintent_nothide:'\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,#varname#_capi);'}, + """\ +\tif (capi_#varname#_tmp == NULL) { +\t\tif (!PyErr_Occurred()) +\t\t\tPyErr_SetString(#modulename#_error,\"failed in converting #nth# `#varname#\' of #pyname# to C/Fortran array\" ); +\t} else { +\t\t#varname# = (#ctype# *)(capi_#varname#_tmp->data); +""", +{hasinitvalue:[ + {isintent_nothide:'\tif (#varname#_capi == Py_None) {'}, + {isintent_hide:'\t{'}, + {iscomplexarray:'\t\t#ctype# capi_c;'}, + """\ +\t\tint *_i,capi_i=0; +\t\tCFUNCSMESS(\"#name#: Initializing #varname#=#init#\\n\"); +\t\tif (initforcomb(capi_#varname#_tmp->dimensions,capi_#varname#_tmp->nd,1)) { +\t\t\twhile ((_i = nextforcomb())) +\t\t\t\t#varname#[capi_i++] = #init#; /* fortran way */ +\t\t} else { +\t\t\tif (!PyErr_Occurred()) +\t\t\t\tPyErr_SetString(#modulename#_error,\"Initialization of #nth# #varname# failed (initforcomb).\"); +\t\t\tf2py_success = 0; +\t\t} +\t} +\tif (f2py_success) {"""]}, + ], + 'cleanupfrompyobj':[ # note that this list will be reversed + '\t} /*if (capi_#varname#_tmp == NULL) ... else of #varname#*/', + {l_not(l_or(isintent_out,isintent_hide)):"""\ +\tif((PyObject *)capi_#varname#_tmp!=#varname#_capi) { +\t\tPy_XDECREF(capi_#varname#_tmp); }"""}, + {l_and(isintent_hide,l_not(isintent_out)):"""\t\tPy_XDECREF(capi_#varname#_tmp);"""}, + {hasinitvalue:'\t} /*if (f2py_success) of #varname# init*/'}, + ], + '_check':isarray, + '_depend':'' + }, +# { # Hidden +# 'freemem':{l_not(isintent_out):'\tPy_XDECREF(capi_#varname#_tmp);'}, +# '_check':l_and(isarray,isintent_hide) +# }, +# Scalararray + { # Common + '_check':l_and(isarray,l_not(iscomplexarray)) + },{ # Not hidden + '_check':l_and(isarray,l_not(iscomplexarray),isintent_nothide) + }, +# Integer*1 array + {'need':'#ctype#', + '_check':isint1array, + '_depend':'' + }, +# Integer*-1 array + {'need':'#ctype#', + '_check':isunsigned_chararray, + '_depend':'' + }, +# Integer*-2 array + {'need':'#ctype#', + '_check':isunsigned_shortarray, + '_depend':'' + }, +# Integer*-8 array + {'need':'#ctype#', + '_check':isunsigned_long_longarray, + '_depend':'' + }, +# Complexarray + {'need':'#ctype#', + '_check':iscomplexarray, + '_depend':'' + }, +# Stringarray + { + 'callfortranappend':{isarrayofstrings:'flen(#varname#),'}, + 'need':'string', + '_check':isstringarray + } + ] + +################# Rules for checking ############### + +check_rules=[ + { + 'frompyobj':{debugcapi:'\tfprintf(stderr,\"debug-capi:Checking `#check#\'\\n\");'}, + 'need':'len..' + },{ + 'frompyobj':'\tCHECKSCALAR(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {', + 'cleanupfrompyobj':'\t} /*CHECKSCALAR(#check#)*/', + 'need':'CHECKSCALAR', + '_check':l_and(isscalar,l_not(iscomplex)), + '_break':'' + },{ + 'frompyobj':'\tCHECKSTRING(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {', + 'cleanupfrompyobj':'\t} /*CHECKSTRING(#check#)*/', + 'need':'CHECKSTRING', + '_check':isstring, + '_break':'' + },{ + 'need':'CHECKARRAY', + 'frompyobj':'\tCHECKARRAY(#check#,\"#check#\",\"#nth# #varname#\") {', + 'cleanupfrompyobj':'\t} /*CHECKARRAY(#check#)*/', + '_check':isarray, + '_break':'' + },{ + 'need':'CHECKGENERIC', + 'frompyobj':'\tCHECKGENERIC(#check#,\"#check#\",\"#nth# #varname#\") {', + 'cleanupfrompyobj':'\t} /*CHECKGENERIC(#check#)*/', + } +] + +########## Applying the rules. No need to modify what follows ############# + +#################### Build C/API module ####################### + +def buildmodule(m,um): + """ + Return + """ + global f2py_version,options + outmess('\tBuilding module "%s"...\n'%(m['name'])) + ret = {} + mod_rules=defmod_rules[:] + vrd=modsign2map(m) + rd=dictappend({'f2py_version':f2py_version},vrd) + funcwrappers = [] + funcwrappers2 = [] # F90 codes + for n in m['interfaced']: + nb=None + for bi in m['body']: + if not bi['block']=='interface': + errmess('buildmodule: Expected interface block. Skipping.\n') + continue + for b in bi['body']: + if b['name']==n: nb=b;break + + if not nb: + errmess('buildmodule: Could not found the body of interfaced routine "%s". Skipping.\n'%(n)) + continue + nb_list = [nb] + if nb.has_key('entry'): + for k,a in nb['entry'].items(): + nb1 = copy.deepcopy(nb) + del nb1['entry'] + nb1['name'] = k + nb1['args'] = a + nb_list.append(nb1) + for nb in nb_list: + api,wrap=buildapi(nb) + if wrap: + if ismoduleroutine(nb): + funcwrappers2.append(wrap) + else: + funcwrappers.append(wrap) + ar=applyrules(api,vrd) + rd=dictappend(rd,ar) + + # Construct COMMON block support + cr,wrap = common_rules.buildhooks(m) + if wrap: + funcwrappers.append(wrap) + ar=applyrules(cr,vrd) + rd=dictappend(rd,ar) + + # Construct F90 module support + mr,wrap = f90mod_rules.buildhooks(m) + if wrap: + funcwrappers2.append(wrap) + ar=applyrules(mr,vrd) + rd=dictappend(rd,ar) + + for u in um: + ar=use_rules.buildusevars(u,m['use'][u['name']]) + rd=dictappend(rd,ar) + + needs=cfuncs.get_needs() + code={} + for n in needs.keys(): + code[n]=[] + for k in needs[n]: + c='' + if cfuncs.includes0.has_key(k): c=cfuncs.includes0[k] + elif cfuncs.includes.has_key(k): c=cfuncs.includes[k] + elif cfuncs.userincludes.has_key(k): c=cfuncs.userincludes[k] + elif cfuncs.typedefs.has_key(k): c=cfuncs.typedefs[k] + elif cfuncs.typedefs_generated.has_key(k): + c=cfuncs.typedefs_generated[k] + elif cfuncs.cppmacros.has_key(k): c=cfuncs.cppmacros[k] + elif cfuncs.cfuncs.has_key(k): c=cfuncs.cfuncs[k] + elif cfuncs.callbacks.has_key(k): c=cfuncs.callbacks[k] + elif cfuncs.f90modhooks.has_key(k): c=cfuncs.f90modhooks[k] + elif cfuncs.commonhooks.has_key(k): c=cfuncs.commonhooks[k] + else: errmess('buildmodule: unknown need %s.\n'%(`k`));continue + code[n].append(c) + mod_rules.append(code) + for r in mod_rules: + if (r.has_key('_check') and r['_check'](m)) or (not r.has_key('_check')): + ar=applyrules(r,vrd,m) + rd=dictappend(rd,ar) + ar=applyrules(module_rules,rd) + + fn = os.path.join(options['buildpath'],vrd['modulename']+'module.c') + ret['csrc'] = fn + f=open(fn,'w') + f.write(string.replace(ar['modulebody'],'\t',2*' ')) + f.close() + outmess('\tWrote C/API module "%s" to file "%s/%smodule.c"\n'%(m['name'],options['buildpath'],vrd['modulename'])) + + if options['dorestdoc']: + fn = os.path.join(options['buildpath'],vrd['modulename']+'module.rest') + f=open(fn,'w') + f.write('.. -*- rest -*-\n') + f.write(string.join(ar['restdoc'],'\n')) + f.close() + outmess('\tReST Documentation is saved to file "%s/%smodule.rest"\n'%(options['buildpath'],vrd['modulename'])) + if options['dolatexdoc']: + fn = os.path.join(options['buildpath'],vrd['modulename']+'module.tex') + ret['ltx'] = fn + f=open(fn,'w') + f.write('%% This file is auto-generated with f2py (version:%s)\n'%(f2py_version)) + if not options.has_key('shortlatex'): + f.write('\\documentclass{article}\n\\usepackage{a4wide}\n\\begin{document}\n\\tableofcontents\n\n') + f.write(string.join(ar['latexdoc'],'\n')) + if not options.has_key('shortlatex'): + f.write('\\end{document}') + f.close() + outmess('\tDocumentation is saved to file "%s/%smodule.tex"\n'%(options['buildpath'],vrd['modulename'])) + if funcwrappers: + wn = os.path.join(options['buildpath'],'%s-f2pywrappers.f'%(vrd['modulename'])) + ret['fsrc'] = wn + f=open(wn,'w') + f.write('C -*- fortran -*-\n') + f.write('C This file is autogenerated with f2py (version:%s)\n'%(f2py_version)) + f.write('C It contains Fortran 77 wrappers to fortran functions.\n') + lines = [] + for l in string.split(string.join(funcwrappers,'\n\n')+'\n','\n'): + if l and l[0]==' ': + while len(l)>=66: + lines.append(l[:66]+'\n &') + l = l[66:] + lines.append(l+'\n') + else: lines.append(l+'\n') + lines = string.join(lines,'').replace('\n &\n','\n') + f.write(lines) + f.close() + outmess('\tFortran 77 wrappers are saved to "%s"\n'%(wn)) + if funcwrappers2: + wn = os.path.join(options['buildpath'],'%s-f2pywrappers2.f90'%(vrd['modulename'])) + ret['fsrc'] = wn + f=open(wn,'w') + f.write('! -*- f90 -*-\n') + f.write('! This file is autogenerated with f2py (version:%s)\n'%(f2py_version)) + f.write('! It contains Fortran 90 wrappers to fortran functions.\n') + lines = [] + for l in string.split(string.join(funcwrappers2,'\n\n')+'\n','\n'): + if len(l)>72 and l[0]==' ': + lines.append(l[:72]+'&\n &') + l = l[72:] + while len(l)>66: + lines.append(l[:66]+'&\n &') + l = l[66:] + lines.append(l+'\n') + else: lines.append(l+'\n') + lines = string.join(lines,'').replace('\n &\n','\n') + f.write(lines) + f.close() + outmess('\tFortran 90 wrappers are saved to "%s"\n'%(wn)) + return ret + +################## Build C/API function ############# + +stnd={1:'st',2:'nd',3:'rd',4:'th',5:'th',6:'th',7:'th',8:'th',9:'th',0:'th'} +def buildapi(rout): + rout,wrap = func2subr.assubr(rout) + args,depargs=getargs2(rout) + capi_maps.depargs=depargs + var=rout['vars'] + auxvars = [a for a in var.keys() if isintent_aux(var[a])] + + if ismoduleroutine(rout): + outmess('\t\t\tConstructing wrapper function "%s.%s"...\n'%(rout['modulename'],rout['name'])) + else: + outmess('\t\tConstructing wrapper function "%s"...\n'%(rout['name'])) + # Routine + vrd=routsign2map(rout) + rd=dictappend({},vrd) + for r in rout_rules: + if (r.has_key('_check') and r['_check'](rout)) or (not r.has_key('_check')): + ar=applyrules(r,vrd,rout) + rd=dictappend(rd,ar) + + # Args + nth,nthk=0,0 + savevrd={} + for a in args: + vrd=sign2map(a,var[a]) + if isintent_aux(var[a]): + _rules = aux_rules + else: + _rules = arg_rules + if not isintent_hide(var[a]): + if not isoptional(var[a]): + nth=nth+1 + vrd['nth']=`nth`+stnd[nth%10]+' argument' + else: + nthk=nthk+1 + vrd['nth']=`nthk`+stnd[nthk%10]+' keyword' + else: vrd['nth']='hidden' + savevrd[a]=vrd + for r in _rules: + if r.has_key('_depend'): continue + if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')): + ar=applyrules(r,vrd,var[a]) + rd=dictappend(rd,ar) + if r.has_key('_break'): break + for a in depargs: + if isintent_aux(var[a]): + _rules = aux_rules + else: + _rules = arg_rules + vrd=savevrd[a] + for r in _rules: + if not r.has_key('_depend'): continue + if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')): + ar=applyrules(r,vrd,var[a]) + rd=dictappend(rd,ar) + if r.has_key('_break'): break + if var[a].has_key('check'): + for c in var[a]['check']: + vrd['check']=c + ar=applyrules(check_rules,vrd,var[a]) + rd=dictappend(rd,ar) + if type(rd['cleanupfrompyobj']) is types.ListType: + rd['cleanupfrompyobj'].reverse() + if type(rd['closepyobjfrom']) is types.ListType: + rd['closepyobjfrom'].reverse() + rd['docsignature']=stripcomma(replace('#docsign##docsignopt##docsignxa#', + {'docsign':rd['docsign'], + 'docsignopt':rd['docsignopt'], + 'docsignxa':rd['docsignxa']})) + optargs=stripcomma(replace('#docsignopt##docsignxa#', + {'docsignxa':rd['docsignxashort'], + 'docsignopt':rd['docsignoptshort']} + )) + if optargs=='': + rd['docsignatureshort']=stripcomma(replace('#docsign#',{'docsign':rd['docsign']})) + else: + rd['docsignatureshort']=replace('#docsign#[#docsignopt#]', + {'docsign':rd['docsign'], + 'docsignopt':optargs, + }) + rd['latexdocsignatureshort']=string.replace(rd['docsignatureshort'],'_','\\_') + rd['latexdocsignatureshort']=string.replace(rd['latexdocsignatureshort'],',',', ') + cfs=stripcomma(replace('#callfortran##callfortranappend#',{'callfortran':rd['callfortran'],'callfortranappend':rd['callfortranappend']})) + if len(rd['callfortranappend'])>1: + rd['callcompaqfortran']=stripcomma(replace('#callfortran# 0,#callfortranappend#',{'callfortran':rd['callfortran'],'callfortranappend':rd['callfortranappend']})) + else: + rd['callcompaqfortran']=cfs + rd['callfortran']=cfs + if type(rd['docreturn'])==types.ListType: + rd['docreturn']=stripcomma(replace('#docreturn#',{'docreturn':rd['docreturn']}))+' = ' + rd['docstrsigns']=[] + rd['latexdocstrsigns']=[] + for k in ['docstrreq','docstropt','docstrout','docstrcbs']: + if rd.has_key(k) and type(rd[k])==types.ListType: + rd['docstrsigns']=rd['docstrsigns']+rd[k] + k='latex'+k + if rd.has_key(k) and type(rd[k])==types.ListType: + rd['latexdocstrsigns']=rd['latexdocstrsigns']+rd[k][0:1]+\ + ['\\begin{description}']+rd[k][1:]+\ + ['\\end{description}'] + ar=applyrules(routine_rules,rd) + if ismoduleroutine(rout): + outmess('\t\t\t %s\n'%(ar['docshort'])) + else: + outmess('\t\t %s\n'%(ar['docshort'])) + return ar,wrap + + +#################### EOF rules.py ####################### diff --git a/numpy/f2py/setup.cfg b/numpy/f2py/setup.cfg new file mode 100644 index 000000000..14669544c --- /dev/null +++ b/numpy/f2py/setup.cfg @@ -0,0 +1,3 @@ +[bdist_rpm] +doc_files = docs/ + tests/
\ No newline at end of file diff --git a/numpy/f2py/setup.py b/numpy/f2py/setup.py new file mode 100755 index 000000000..2616ccbd5 --- /dev/null +++ b/numpy/f2py/setup.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +""" +setup.py for installing F2PY + +Usage: + python setup.py install + +Copyright 2001-2005 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.32 $ +$Date: 2005/01/30 17:22:14 $ +Pearu Peterson +""" + +__version__ = "$Id: setup.py,v 1.32 2005/01/30 17:22:14 pearu Exp $" + +import os +import sys +from distutils.dep_util import newer +from scipy.distutils.core import setup +from scipy.distutils.misc_util import Configuration + +from __version__ import version + +def configuration(parent_package='',top_path=None): + config = Configuration('f2py', parent_package, top_path) + + config.add_data_dir('docs') + + config.add_data_files('src/fortranobject.c', + 'src/fortranobject.h', + 'f2py.1' + ) + + config.make_svn_version_py() + + def generate_f2py_py(build_dir): + f2py_exe = 'f2py'+os.path.basename(sys.executable)[6:] + if f2py_exe[-4:]=='.exe': + f2py_exe = f2py_exe[:-4] + '.py' + if 'bdist_wininst' in sys.argv and f2py_exe[-3:] != '.py': + f2py_exe = f2py_exe + '.py' + target = os.path.join(build_dir,f2py_exe) + if newer(__file__,target): + print 'Creating',target + f = open(target,'w') + f.write('''\ +#!/usr/bin/env %s +# See http://cens.ioc.ee/projects/f2py2e/ +import os +os.environ["NO_SCIPY_IMPORT"]="f2py" +import scipy.f2py as f2py +f2py.main() +'''%(os.path.basename(sys.executable))) + f.close() + return target + + config.add_scripts(generate_f2py_py) + + print 'F2PY Version',config.get_version() + + return config + +if __name__ == "__main__": + + config = configuration(top_path='') + version = config.get_version() + print 'F2PY Version',version + config = config.todict() + + if sys.version[:3]>='2.3': + config['download_url'] = "http://cens.ioc.ee/projects/f2py2e/2.x"\ + "/F2PY-2-latest.tar.gz" + config['classifiers'] = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: C', + 'Programming Language :: Fortran', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering', + 'Topic :: Software Development :: Code Generators', + ] + setup(version=version, + description = "F2PY - Fortran to Python Interface Generaton", + author = "Pearu Peterson", + author_email = "pearu@cens.ioc.ee", + maintainer = "Pearu Peterson", + maintainer_email = "pearu@cens.ioc.ee", + license = "LGPL", + platforms = "Unix, Windows (mingw|cygwin), Mac OSX", + long_description = """\ +The Fortran to Python Interface Generator, or F2PY for short, is a +command line tool (f2py) for generating Python C/API modules for +wrapping Fortran 77/90/95 subroutines, accessing common blocks from +Python, and calling Python functions from Fortran (call-backs). +Interfacing subroutines/data from Fortran 90/95 modules is supported.""", + url = "http://cens.ioc.ee/projects/f2py2e/", + keywords = ['Fortran','f2py'], + **config) diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c new file mode 100644 index 000000000..d5da43a88 --- /dev/null +++ b/numpy/f2py/src/fortranobject.c @@ -0,0 +1,756 @@ +#define FORTRANOBJECT_C +#include "fortranobject.h" + +#ifdef __cplusplus +extern "C" { +#endif +/* + This file implements: FortranObject, array_from_pyobj, copy_ND_array + + Author: Pearu Peterson <pearu@cens.ioc.ee> + $Revision: 1.52 $ + $Date: 2005/07/11 07:44:20 $ +*/ + +/************************* FortranObject *******************************/ + +typedef PyObject *(*fortranfunc)(PyObject *,PyObject *,PyObject *,void *); + +PyObject * +PyFortranObject_New(FortranDataDef* defs, f2py_void_func init) { + int i; + PyFortranObject *fp = NULL; + PyObject *v = NULL; + if (init!=NULL) /* Initialize F90 module objects */ + (*(init))(); + if ((fp = PyObject_New(PyFortranObject, &PyFortran_Type))==NULL) return NULL; + if ((fp->dict = PyDict_New())==NULL) return NULL; + fp->len = 0; + while (defs[fp->len].name != NULL) fp->len++; + if (fp->len == 0) goto fail; + fp->defs = defs; + for (i=0;i<fp->len;i++) + if (fp->defs[i].rank == -1) { /* Is Fortran routine */ + v = PyFortranObject_NewAsAttr(&(fp->defs[i])); + if (v==NULL) return NULL; + PyDict_SetItemString(fp->dict,fp->defs[i].name,v); + } else + if ((fp->defs[i].data)!=NULL) { /* Is Fortran variable or array (not allocatable) */ + v = PyArray_New(&PyArray_Type, fp->defs[i].rank, fp->defs[i].dims.d, + fp->defs[i].type, NULL, fp->defs[i].data, 0, FARRAY_FLAGS, + NULL); + if (v==NULL) return NULL; + PyDict_SetItemString(fp->dict,fp->defs[i].name,v); + } + Py_XDECREF(v); + return (PyObject *)fp; + fail: + Py_XDECREF(v); + return NULL; +} + +PyObject * +PyFortranObject_NewAsAttr(FortranDataDef* defs) { /* used for calling F90 module routines */ + PyFortranObject *fp = NULL; + fp = PyObject_New(PyFortranObject, &PyFortran_Type); + if (fp == NULL) return NULL; + if ((fp->dict = PyDict_New())==NULL) return NULL; + fp->len = 1; + fp->defs = defs; + return (PyObject *)fp; +} + +/* Fortran methods */ + +static void +fortran_dealloc(PyFortranObject *fp) { + Py_XDECREF(fp->dict); + PyMem_Del(fp); +} + + +static PyMethodDef fortran_methods[] = { + {NULL, NULL} /* sentinel */ +}; + + +static PyObject * +fortran_doc (FortranDataDef def) { + char *p; + PyObject *s = NULL; + int i; + unsigned size=100; + if (def.doc!=NULL) + size += strlen(def.doc); + p = (char*)malloc (size); + if (sprintf(p,"%s - ",def.name)==0) goto fail; + if (def.rank==-1) { + if (def.doc==NULL) { + if (sprintf(p,"%sno docs available",p)==0) + goto fail; + } else { + if (sprintf(p,"%s%s",p,def.doc)==0) + goto fail; + } + } else { + PyArray_Descr *d = PyArray_DescrFromType(def.type); + if (sprintf(p,"%s'%c'-",p,d->type)==0) goto fail; + if (def.data==NULL) { + if (sprintf(p,"%sarray(%" INTP_FMT,p,def.dims.d[0])==0) goto fail; + for(i=1;i<def.rank;++i) + if (sprintf(p,"%s,%" INTP_FMT,p,def.dims.d[i])==0) goto fail; + if (sprintf(p,"%s), not allocated",p)==0) goto fail; + } else { + if (def.rank>0) { + if (sprintf(p,"%sarray(%"INTP_FMT,p,def.dims.d[0])==0) goto fail; + for(i=1;i<def.rank;i++) + if (sprintf(p,"%s,%" INTP_FMT,p,def.dims.d[i])==0) goto fail; + if (sprintf(p,"%s)",p)==0) goto fail; + } else { + if (sprintf(p,"%sscalar",p)==0) goto fail; + } + } + } + if (sprintf(p,"%s\n",p)==0) goto fail; + if (strlen(p)>size) { + fprintf(stderr,"fortranobject.c:fortran_doc:len(p)=%zd>%d(size): too long doc string required, increase size\n",strlen(p),size); + goto fail; + } + s = PyString_FromString(p); + fail: + free(p); + return s; +} + +static FortranDataDef *save_def; /* save pointer of an allocatable array */ +static void set_data(char *d,intp *f) { /* callback from Fortran */ + if (*f) /* In fortran f=allocated(d) */ + save_def->data = d; + else + save_def->data = NULL; + /* printf("set_data: d=%p,f=%d\n",d,*f); */ +} + +static PyObject * +fortran_getattr(PyFortranObject *fp, char *name) { + int i,j,k,flag; + if (fp->dict != NULL) { + PyObject *v = PyDict_GetItemString(fp->dict, name); + if (v != NULL) { + Py_INCREF(v); + return v; + } + } + for (i=0,j=1;i<fp->len && (j=strcmp(name,fp->defs[i].name));i++); + if (j==0) + if (fp->defs[i].rank!=-1) { /* F90 allocatable array */ + if (fp->defs[i].func==NULL) return NULL; + for(k=0;k<fp->defs[i].rank;++k) + fp->defs[i].dims.d[k]=-1; + save_def = &fp->defs[i]; + (*(fp->defs[i].func))(&fp->defs[i].rank,fp->defs[i].dims.d,set_data,&flag); + if (flag==2) + k = fp->defs[i].rank + 1; + else + k = fp->defs[i].rank; + if (fp->defs[i].data !=NULL) { /* array is allocated */ + PyObject *v = PyArray_New(&PyArray_Type, k, fp->defs[i].dims.d, + fp->defs[i].type, NULL, fp->defs[i].data, 0, FARRAY_FLAGS, + NULL); + if (v==NULL) return NULL; + /* Py_INCREF(v); */ + return v; + } else { /* array is not allocated */ + Py_INCREF(Py_None); + return Py_None; + } + } + if (strcmp(name,"__dict__")==0) { + Py_INCREF(fp->dict); + return fp->dict; + } + if (strcmp(name,"__doc__")==0) { + PyObject *s = PyString_FromString(""); + for (i=0;i<fp->len;i++) + PyString_ConcatAndDel(&s,fortran_doc(fp->defs[i])); + if (PyDict_SetItemString(fp->dict, name, s)) + return NULL; + return s; + } + if ((strcmp(name,"_cpointer")==0) && (fp->len==1)) { + PyObject *cobj = PyCObject_FromVoidPtr((void *)(fp->defs[0].data),NULL); + if (PyDict_SetItemString(fp->dict, name, cobj)) + return NULL; + return cobj; + } + return Py_FindMethod(fortran_methods, (PyObject *)fp, name); +} + +static int +fortran_setattr(PyFortranObject *fp, char *name, PyObject *v) { + int i,j,flag; + PyArrayObject *arr = NULL; + for (i=0,j=1;i<fp->len && (j=strcmp(name,fp->defs[i].name));i++); + if (j==0) { + if (fp->defs[i].rank==-1) { + PyErr_SetString(PyExc_AttributeError,"over-writing fortran routine"); + return -1; + } + if (fp->defs[i].func!=NULL) { /* is allocatable array */ + intp dims[F2PY_MAX_DIMS]; + int k; + save_def = &fp->defs[i]; + if (v!=Py_None) { /* set new value (reallocate if needed -- + see f2py generated code for more + details ) */ + for(k=0;k<fp->defs[i].rank;k++) dims[k]=-1; + if ((arr = array_from_pyobj(fp->defs[i].type,dims,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) + return -1; + (*(fp->defs[i].func))(&fp->defs[i].rank,arr->dimensions,set_data,&flag); + } else { /* deallocate */ + for(k=0;k<fp->defs[i].rank;k++) dims[k]=0; + (*(fp->defs[i].func))(&fp->defs[i].rank,dims,set_data,&flag); + for(k=0;k<fp->defs[i].rank;k++) dims[k]=-1; + } + memcpy(fp->defs[i].dims.d,dims,fp->defs[i].rank*sizeof(intp)); + } else { /* not allocatable array */ + if ((arr = array_from_pyobj(fp->defs[i].type,fp->defs[i].dims.d,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) + return -1; + } + if (fp->defs[i].data!=NULL) { /* copy Python object to Fortran array */ + intp s = PyArray_MultiplyList(fp->defs[i].dims.d,arr->nd); + if (s==-1) + s = PyArray_MultiplyList(arr->dimensions,arr->nd); + if (s<0 || + (memcpy(fp->defs[i].data,arr->data,s*PyArray_ITEMSIZE(arr)))==NULL) { + if ((PyObject*)arr!=v) { + Py_DECREF(arr); + } + return -1; + } + if ((PyObject*)arr!=v) { + Py_DECREF(arr); + } + } else return (fp->defs[i].func==NULL?-1:0); + return 0; /* succesful */ + } + if (fp->dict == NULL) { + fp->dict = PyDict_New(); + if (fp->dict == NULL) + return -1; + } + if (v == NULL) { + int rv = PyDict_DelItemString(fp->dict, name); + if (rv < 0) + PyErr_SetString(PyExc_AttributeError,"delete non-existing fortran attribute"); + return rv; + } + else + return PyDict_SetItemString(fp->dict, name, v); +} + +static PyObject* +fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw) { + int i = 0; + /* printf("fortran call + name=%s,func=%p,data=%p,%p\n",fp->defs[i].name, + fp->defs[i].func,fp->defs[i].data,&fp->defs[i].data); */ + if (fp->defs[i].rank==-1) {/* is Fortran routine */ + if ((fp->defs[i].func==NULL)) { + PyErr_Format(PyExc_RuntimeError, "no function to call"); + return NULL; + } + else if (fp->defs[i].data==NULL) + /* dummy routine */ + return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw,NULL); + else + return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw, + (void *)fp->defs[i].data); + } + PyErr_Format(PyExc_TypeError, "this fortran object is not callable"); + return NULL; +} + + +PyTypeObject PyFortran_Type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + "fortran", /*tp_name*/ + sizeof(PyFortranObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)fortran_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)fortran_getattr, /*tp_getattr*/ + (setattrfunc)fortran_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + (ternaryfunc)fortran_call, /*tp_call*/ +}; + +/************************* f2py_report_atexit *******************************/ + +#ifdef F2PY_REPORT_ATEXIT +static int passed_time = 0; +static int passed_counter = 0; +static int passed_call_time = 0; +static struct timeb start_time; +static struct timeb stop_time; +static struct timeb start_call_time; +static struct timeb stop_call_time; +static int cb_passed_time = 0; +static int cb_passed_counter = 0; +static int cb_passed_call_time = 0; +static struct timeb cb_start_time; +static struct timeb cb_stop_time; +static struct timeb cb_start_call_time; +static struct timeb cb_stop_call_time; + +extern void f2py_start_clock(void) { ftime(&start_time); } +extern +void f2py_start_call_clock(void) { + f2py_stop_clock(); + ftime(&start_call_time); +} +extern +void f2py_stop_clock(void) { + ftime(&stop_time); + passed_time += 1000*(stop_time.time - start_time.time); + passed_time += stop_time.millitm - start_time.millitm; +} +extern +void f2py_stop_call_clock(void) { + ftime(&stop_call_time); + passed_call_time += 1000*(stop_call_time.time - start_call_time.time); + passed_call_time += stop_call_time.millitm - start_call_time.millitm; + passed_counter += 1; + f2py_start_clock(); +} + +extern void f2py_cb_start_clock(void) { ftime(&cb_start_time); } +extern +void f2py_cb_start_call_clock(void) { + f2py_cb_stop_clock(); + ftime(&cb_start_call_time); +} +extern +void f2py_cb_stop_clock(void) { + ftime(&cb_stop_time); + cb_passed_time += 1000*(cb_stop_time.time - cb_start_time.time); + cb_passed_time += cb_stop_time.millitm - cb_start_time.millitm; +} +extern +void f2py_cb_stop_call_clock(void) { + ftime(&cb_stop_call_time); + cb_passed_call_time += 1000*(cb_stop_call_time.time - cb_start_call_time.time); + cb_passed_call_time += cb_stop_call_time.millitm - cb_start_call_time.millitm; + cb_passed_counter += 1; + f2py_cb_start_clock(); +} + +static int f2py_report_on_exit_been_here = 0; +extern +void f2py_report_on_exit(int exit_flag,void *name) { + if (f2py_report_on_exit_been_here) { + fprintf(stderr," %s\n",(char*)name); + return; + } + f2py_report_on_exit_been_here = 1; + fprintf(stderr," /-----------------------\\\n"); + fprintf(stderr," < F2PY performance report >\n"); + fprintf(stderr," \\-----------------------/\n"); + fprintf(stderr,"Overall time spent in ...\n"); + fprintf(stderr,"(a) wrapped (Fortran/C) functions : %8d msec\n", + passed_call_time); + fprintf(stderr,"(b) f2py interface, %6d calls : %8d msec\n", + passed_counter,passed_time); + fprintf(stderr,"(c) call-back (Python) functions : %8d msec\n", + cb_passed_call_time); + fprintf(stderr,"(d) f2py call-back interface, %6d calls : %8d msec\n", + cb_passed_counter,cb_passed_time); + + fprintf(stderr,"(e) wrapped (Fortran/C) functions (acctual) : %8d msec\n\n", + passed_call_time-cb_passed_call_time-cb_passed_time); + fprintf(stderr,"Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n"); + fprintf(stderr,"Exit status: %d\n",exit_flag); + fprintf(stderr,"Modules : %s\n",(char*)name); +} +#endif + +/********************** report on array copy ****************************/ + +#ifdef F2PY_REPORT_ON_ARRAY_COPY +static void f2py_report_on_array_copy(PyArrayObject* arr) { + const long arr_size = PyArray_Size((PyObject *)arr); + if (arr_size>F2PY_REPORT_ON_ARRAY_COPY) { + fprintf(stderr,"copied an array: size=%ld, elsize=%d\n", + arr_size, PyArray_ITEMSIZE(arr)); + } +} +static void f2py_report_on_array_copy_fromany(void) { + fprintf(stderr,"created an array from object\n"); +} + +#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR f2py_report_on_array_copy((PyArrayObject *)arr) +#define F2PY_REPORT_ON_ARRAY_COPY_FROMANY f2py_report_on_array_copy_fromany() +#else +#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR +#define F2PY_REPORT_ON_ARRAY_COPY_FROMANY +#endif + + +/************************* array_from_obj *******************************/ + +/* + * File: array_from_pyobj.c + * + * Description: + * ------------ + * Provides array_from_pyobj function that returns a contigious array + * object with the given dimensions and required storage order, either + * in row-major (C) or column-major (Fortran) order. The function + * array_from_pyobj is very flexible about its Python object argument + * that can be any number, list, tuple, or array. + * + * array_from_pyobj is used in f2py generated Python extension + * modules. + * + * Author: Pearu Peterson <pearu@cens.ioc.ee> + * Created: 13-16 January 2002 + * $Id: fortranobject.c,v 1.52 2005/07/11 07:44:20 pearu Exp $ + */ + +static int +count_nonpos(const int rank, + const intp *dims) { + int i=0,r=0; + while (i<rank) { + if (dims[i] <= 0) ++r; + ++i; + } + return r; +} + +static int check_and_fix_dimensions(const PyArrayObject* arr, + const int rank, + intp *dims); + +#ifdef DEBUG_COPY_ND_ARRAY +void dump_attrs(const PyArrayObject* arr) { + int rank = arr->nd; + intp size = PyArray_Size((PyObject *)arr); + int i; + printf("\trank = %d, flags = %d, size = %" INTP_FMT "\n", + rank,arr->flags,size); + printf("\tstrides = ["); + for(i=0;i<rank;++i) { + printf("%3" INTP_FMT,arr->strides[i]); + } + printf("]\n\t dimensions = ["); + for(i=0;i<rank;++i) { + printf("%3" INTP_FMT, arr->dimensions[i]); + } + printf("]\n"); +} +#endif + +#define SWAPTYPE(a,b,t) {t c; c = (a); (a) = (b); (b) = c; } + +static int swap_arrays(PyArrayObject* arr1, PyArrayObject* arr2) { + SWAPTYPE(arr1->data,arr2->data,char*); + SWAPTYPE(arr1->nd,arr2->nd,int); + SWAPTYPE(arr1->dimensions,arr2->dimensions,intp*); + SWAPTYPE(arr1->strides,arr2->strides,intp*); + SWAPTYPE(arr1->base,arr2->base,PyObject*); + SWAPTYPE(arr1->descr,arr2->descr,PyArray_Descr*); + SWAPTYPE(arr1->flags,arr2->flags,int); + /* SWAPTYPE(arr1->weakreflist,arr2->weakreflist,PyObject*); */ + return 0; +} + +#define ARRAY_ISCOMPATIBLE(arr,type_num) \ +( (PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) \ + ||(PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) \ + ||(PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) \ +) + +extern +PyArrayObject* array_from_pyobj(const int type_num, + intp *dims, + const int rank, + const int intent, + PyObject *obj) { + /* Note about reference counting + ----------------------------- + If the caller returns the array to Python, it must be done with + Py_BuildValue("N",arr). + Otherwise, if obj!=arr then the caller must call Py_DECREF(arr). + + Note on intent(cache,out,..) + --------------------- + Don't expect correct data when returning intent(cache) array. + + */ + char mess[200]; + PyArrayObject *arr = NULL; + PyArray_Descr *descr = PyArray_DescrFromType(type_num); + + if ((intent & F2PY_INTENT_HIDE) + || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None)) + || ((intent & F2PY_OPTIONAL) && (obj==Py_None)) + ) { + /* intent(cache), optional, intent(hide) */ + if (count_nonpos(rank,dims)) { + int i; + sprintf(mess,"failed to create intent(cache|hide)|optional array" + "-- must have defined dimensions but got ("); + for(i=0;i<rank;++i) + sprintf(mess+strlen(mess),"%" INTP_FMT ",",dims[i]); + sprintf(mess+strlen(mess),")"); + PyErr_SetString(PyExc_ValueError,mess); + return NULL; + } + arr = (PyArrayObject *) + PyArray_New(&PyArray_Type, rank, dims, type_num, + NULL,NULL,0, + !(intent&F2PY_INTENT_C), + NULL); + if (!(intent & F2PY_INTENT_CACHE)) + PyArray_FILLWBYTE(arr, 0); + return arr; + } + + if (PyArray_Check(obj)) { + arr = (PyArrayObject *)obj; + + if (intent & F2PY_INTENT_CACHE) { + /* intent(cache) */ + if (PyArray_ISONESEGMENT(obj) + && PyArray_ITEMSIZE((PyArrayObject *)obj)>=descr->elsize) { + if (check_and_fix_dimensions((PyArrayObject *)obj,rank,dims)) + return NULL; /*XXX: set exception */ + if (intent & F2PY_INTENT_OUT) + Py_INCREF(obj); + return (PyArrayObject *)obj; + } + sprintf(mess,"failed to initialize intent(cache) array"); + if (!PyArray_ISONESEGMENT(obj)) + sprintf(mess+strlen(mess)," -- input must be in one segment"); + if (PyArray_ITEMSIZE(arr)<descr->elsize) + sprintf(mess+strlen(mess)," -- expected at least elsize=%d but got %d", + descr->elsize,PyArray_ITEMSIZE(arr) + ); + PyErr_SetString(PyExc_ValueError,mess); + return NULL; + } + + /* here we have always intent(in) or intent(inout) or intent(inplace) */ + + if (check_and_fix_dimensions(arr,rank,dims)) + return NULL; /*XXX: set exception */ + + if ((! (intent & F2PY_INTENT_COPY)) + && PyArray_ITEMSIZE(arr)==descr->elsize + && ARRAY_ISCOMPATIBLE(arr,type_num) + ) { + if ((intent & F2PY_INTENT_C)?PyArray_ISCARRAY(arr):PyArray_ISFARRAY(arr)) { + if ((intent & F2PY_INTENT_OUT)) { + Py_INCREF(arr); + } + /* Returning input array */ + return arr; + } + } + + if (intent & F2PY_INTENT_INOUT) { + sprintf(mess,"failed to initialize intent(inout) array"); + if ((intent & F2PY_INTENT_C) && !PyArray_ISCARRAY(arr)) + sprintf(mess+strlen(mess)," -- input not contiguous"); + if (!(intent & F2PY_INTENT_C) && !PyArray_ISFARRAY(arr)) + sprintf(mess+strlen(mess)," -- input not fortran contiguous"); + if (PyArray_ITEMSIZE(arr)!=descr->elsize) + sprintf(mess+strlen(mess)," -- expected elsize=%d but got %d", + descr->elsize, + PyArray_ITEMSIZE(arr) + ); + if (!(ARRAY_ISCOMPATIBLE(arr,type_num))) + sprintf(mess+strlen(mess)," -- input '%c' not compatible to '%c'", + arr->descr->type,descr->type); + PyErr_SetString(PyExc_ValueError,mess); + return NULL; + } + + /* here we have always intent(in) or intent(inplace) */ + + { + PyArrayObject *retarr = (PyArrayObject *) \ + PyArray_New(&PyArray_Type, arr->nd, arr->dimensions, type_num, + NULL,NULL,0, + !(intent&F2PY_INTENT_C), + NULL); + if (retarr==NULL) + return NULL; + F2PY_REPORT_ON_ARRAY_COPY_FROMARR; + if (PyArray_CopyInto(retarr, arr)) { + Py_DECREF(retarr); + return NULL; + } + if (intent & F2PY_INTENT_INPLACE) { + if (swap_arrays(arr,retarr)) + return NULL; /* XXX: set exception */ + Py_XDECREF(retarr); + if (intent & F2PY_INTENT_OUT) + Py_INCREF(arr); + } else { + arr = retarr; + } + } + return arr; + } + + if ((intent & F2PY_INTENT_INOUT) + || (intent & F2PY_INTENT_INPLACE) + || (intent & F2PY_INTENT_CACHE)) { + sprintf(mess,"failed to initialize intent(inout|inplace|cache) array" + " -- input must be array but got %s", + PyString_AsString(PyObject_Str(PyObject_Type(obj))) + ); + PyErr_SetString(PyExc_TypeError,mess); + return NULL; + } + + { + F2PY_REPORT_ON_ARRAY_COPY_FROMANY; + arr = (PyArrayObject *) \ + PyArray_FromAny(obj,PyArray_DescrFromType(type_num), 0,0, + ((intent & F2PY_INTENT_C)?CARRAY_FLAGS:FARRAY_FLAGS) \ + | FORCECAST ); + if (arr==NULL) + return NULL; + if (check_and_fix_dimensions(arr,rank,dims)) + return NULL; /*XXX: set exception */ + return arr; + } + +} + + /*****************************************/ + /* Helper functions for array_from_pyobj */ + /*****************************************/ + +static +int check_and_fix_dimensions(const PyArrayObject* arr,const int rank,intp *dims) { + /* + This function fills in blanks (that are -1\'s) in dims list using + the dimensions from arr. It also checks that non-blank dims will + match with the corresponding values in arr dimensions. + */ + const intp arr_size = (arr->nd)?PyArray_Size((PyObject *)arr):1; + + if (rank > arr->nd) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */ + intp new_size = 1; + int free_axe = -1; + int i; + /* Fill dims where -1 or 0; check dimensions; calc new_size; */ + for(i=0;i<arr->nd;++i) { + if (dims[i] >= 0) { + if (dims[i]!=arr->dimensions[i]) { + fprintf(stderr,"%d-th dimension must be fixed to %" INTP_FMT + " but got %" INTP_FMT "\n", + i,dims[i], arr->dimensions[i]); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else { + dims[i] = arr->dimensions[i] ? arr->dimensions[i] : 1; + } + new_size *= dims[i]; + } + for(i=arr->nd;i<rank;++i) + if (dims[i]>1) { + fprintf(stderr,"%d-th dimension must be %" INTP_FMT + " but got 0 (not defined).\n", + i,dims[i]); + return 1; + } else if (free_axe<0) + free_axe = i; + else + dims[i] = 1; + if (free_axe>=0) { + dims[free_axe] = arr_size/new_size; + new_size *= dims[free_axe]; + } + if (new_size != arr_size) { + fprintf(stderr,"confused: new_size=%" INTP_FMT + ", arr_size=%" INTP_FMT " (maybe too many free" + " indices)\n", new_size,arr_size); + return 1; + } + } else { /* [[1,2]] -> [[1],[2]] */ + int i,j; + intp d; + int effrank; + intp size; + for (i=0,effrank=0;i<arr->nd;++i) + if (arr->dimensions[i]>1) ++effrank; + if (dims[rank-1]>=0) + if (effrank>rank) { + fprintf(stderr,"too many axes: %d (effrank=%d), expected rank=%d\n", + arr->nd,effrank,rank); + return 1; + } + for (i=0,j=0;i<rank;++i) { + while (j<arr->nd && arr->dimensions[j]<2) ++j; + if (j>=arr->nd) d = 1; + else d = arr->dimensions[j++]; + if (dims[i]>=0) { + if (d>1 && d!=dims[i]) { + fprintf(stderr,"%d-th dimension must be fixed to %" INTP_FMT + " but got %" INTP_FMT " (real index=%d)\n", + i,dims[i],d,j-1); + return 1; + } + if (!dims[i]) dims[i] = 1; + } else + dims[i] = d; + } + for (i=rank;i<arr->nd;++i) { /* [[1,2],[3,4]] -> [1,2,3,4] */ + while (j<arr->nd && arr->dimensions[j]<2) ++j; + if (j>=arr->nd) d = 1; + else d = arr->dimensions[j++]; + dims[rank-1] *= d; + } + for (i=0,size=1;i<rank;++i) size *= dims[i]; + if (size != arr_size) { + fprintf(stderr,"confused: size=%" INTP_FMT ", arr_size=%" INTP_FMT + ", rank=%d, effrank=%d, arr.nd=%d, dims=[", + size,arr_size,rank,effrank,arr->nd); + for (i=0;i<rank;++i) fprintf(stderr," %" INTP_FMT,dims[i]); + fprintf(stderr," ], arr.dims=["); + for (i=0;i<arr->nd;++i) fprintf(stderr," %" INTP_FMT,arr->dimensions[i]); + fprintf(stderr," ]\n"); + return 1; + } + } + return 0; +} + +/* End of file: array_from_pyobj.c */ + +/************************* copy_ND_array *******************************/ + +extern +int copy_ND_array(const PyArrayObject *arr, PyArrayObject *out) +{ + F2PY_REPORT_ON_ARRAY_COPY_FROMARR; + return PyArray_CopyInto(out, (PyArrayObject *)arr); +} + +#ifdef __cplusplus +} +#endif +/************************* EOF fortranobject.c *******************************/ diff --git a/numpy/f2py/src/fortranobject.h b/numpy/f2py/src/fortranobject.h new file mode 100644 index 000000000..680e6690e --- /dev/null +++ b/numpy/f2py/src/fortranobject.h @@ -0,0 +1,123 @@ +#ifndef Py_FORTRANOBJECT_H +#define Py_FORTRANOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "Python.h" + +#ifdef FORTRANOBJECT_C +#define NO_IMPORT_ARRAY +#endif +#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API +#include "scipy/arrayobject.h" + + /* +#ifdef F2PY_REPORT_ATEXIT_DISABLE +#undef F2PY_REPORT_ATEXIT +#else + +#ifndef __FreeBSD__ +#ifndef __WIN32__ +#ifndef __APPLE__ +#define F2PY_REPORT_ATEXIT +#endif +#endif +#endif + +#endif + */ + +#ifdef F2PY_REPORT_ATEXIT +#include <sys/timeb.h> + extern void f2py_start_clock(void); + extern void f2py_stop_clock(void); + extern void f2py_start_call_clock(void); + extern void f2py_stop_call_clock(void); + extern void f2py_cb_start_clock(void); + extern void f2py_cb_stop_clock(void); + extern void f2py_cb_start_call_clock(void); + extern void f2py_cb_stop_call_clock(void); + extern void f2py_report_on_exit(int,void*); +#endif + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/* Fortran object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +PyFortranObject represents various Fortran objects: +Fortran (module) routines, COMMON blocks, module data. + +Author: Pearu Peterson <pearu@cens.ioc.ee> +*/ + +#define F2PY_MAX_DIMS 40 + +typedef void (*f2py_set_data_func)(char*,intp*); +typedef void (*f2py_void_func)(void); +typedef void (*f2py_init_func)(int*,intp*,f2py_set_data_func,int*); + + /*typedef void* (*f2py_c_func)(void*,...);*/ + +typedef void *(*f2pycfunc)(void); + +typedef struct { + char *name; /* attribute (array||routine) name */ + int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS, + || rank=-1 for Fortran routine */ + struct {intp d[F2PY_MAX_DIMS];} dims; /* dimensions of the array, || not used */ + int type; /* PyArray_<type> || not used */ + char *data; /* pointer to array || Fortran routine */ + f2py_init_func func; /* initialization function for + allocatable arrays: + func(&rank,dims,set_ptr_func,name,len(name)) + || C/API wrapper for Fortran routine */ + char *doc; /* documentation string; only recommended + for routines. */ +} FortranDataDef; + +typedef struct { + PyObject_HEAD + int len; /* Number of attributes */ + FortranDataDef *defs; /* An array of FortranDataDef's */ + PyObject *dict; /* Fortran object attribute dictionary */ +} PyFortranObject; + +#define PyFortran_Check(op) ((op)->ob_type == &PyFortran_Type) +#define PyFortran_Check1(op) (0==strcmp((op)->ob_type->tp_name,"fortran")) + + extern PyTypeObject PyFortran_Type; + extern PyObject * PyFortranObject_New(FortranDataDef* defs, f2py_void_func init); + extern PyObject * PyFortranObject_NewAsAttr(FortranDataDef* defs); + +#define ISCONTIGUOUS(m) ((m)->flags & CONTIGUOUS) +#define F2PY_INTENT_IN 1 +#define F2PY_INTENT_INOUT 2 +#define F2PY_INTENT_OUT 4 +#define F2PY_INTENT_HIDE 8 +#define F2PY_INTENT_CACHE 16 +#define F2PY_INTENT_COPY 32 +#define F2PY_INTENT_C 64 +#define F2PY_OPTIONAL 128 +#define F2PY_INTENT_INPLACE 256 + + extern PyArrayObject* array_from_pyobj(const int type_num, + intp *dims, + const int rank, + const int intent, + PyObject *obj); + extern int copy_ND_array(const PyArrayObject *in, PyArrayObject *out); + +#ifdef DEBUG_COPY_ND_ARRAY + extern void dump_attrs(const PyArrayObject* arr); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FORTRANOBJECT_H */ diff --git a/numpy/f2py/src/test/Makefile b/numpy/f2py/src/test/Makefile new file mode 100644 index 000000000..0f8869f72 --- /dev/null +++ b/numpy/f2py/src/test/Makefile @@ -0,0 +1,96 @@ +# -*- makefile -*- +# File: Makefile-foo +# Usage: +# make -f Makefile-foo [MODE=opt|debug] +# Notes: +# 1) You must use GNU make; try `gmake ..' if `make' fails. +# 2) This file is auto-generated with f2py (version 2.264). +# f2py is a Fortran to Python Interface Generator (FPIG), Second Edition, +# written by Pearu Peterson <pearu@ioc.ee>. +# See http://cens.ioc.ee/projects/f2py2e/ +# Generation date: Wed Sep 13 16:22:55 2000 +# $Revision: 1.2 $ +# $Date: 2000/09/17 16:10:27 $ + +# Recommendation notes produced by f2py2e/buildmakefile.py: +# *** + +PYINC = -I/numeric/include/python1.5/Numeric -I/numeric/include/python1.5 +INCLUDES = -I.. +LIBS = -L$(shell gcc -v 2>&1 | grep specs | sed -e 's/Reading specs from //g' | sed -e 's/\/specs//g') -lg2c +LIBS=-L$$ABSOFT/lib -lfio -lf77math -lf90math +LIBS=-L/numeric/bin -lvast90 -L/usr/lib/gcc-lib/i586-mandrake-linux/2.95.2 -lg2c + +# Wrapper generator: +F2PY = /home/pearu/bin/f2py-cvs + +# Fortran compiler: Absoft f95 +FC = f95 +FC = f90 +FOPT = +FDEBUG = +FFLAGS = -B108 -YCFRL=1 -YCOM_NAMES=LCS -YCOM_PFX -YCOM_SFX=_ -YEXT_PFX -YEXT_NAMES=LCS +FFLAGS = +# C compiler: cc ('gcc 2.x.x' 2.95.2) +CC = cc +COPT = +CDEBUG = +CFLAGS = -fpic + +# Linker: ld ('GNU ld' 2.9.5) +LD = ld +LDFLAGS = -shared -s +SO = .so + +ifeq '$(MODE)' 'debug' +FFLAGS += $(FDEBUG) +CFLAGS += $(CDEBUG) +endif +ifeq '$(MODE)' 'opt' +FFLAGS += $(FOPT) +CFLAGS += $(COPT) +endif +FFLAGS += $(INCLUDES) +CFLAGS += $(PYINC) $(INCLUDES) + +SRCC = ../fortranobject.c +SRCF = mod.f90 bar.f foo90.f90 wrap.f +SRCS = $(SRCC) $(SRCF) +OBJC = $(filter %.o,$(SRCC:.c=.o) $(SRCC:.cc=.o) $(SRCC:.C=.o)) +OBJF = $(filter %.o,$(SRCF:.f90=.o) $(SRCF:.f=.o) $(SRCF:.F=.o) $(SRCF:.for=.o)) +OBJS = $(OBJC) $(OBJF) + +INSTALLNAME = f2py2e-apps +INSTALLDIRECTORY = /numeric/lib/python1.5/site-packages/$(INSTALLNAME) +INSTALLDIR = install -d -c +INSTALLEXEC = install -m 755 -c + +all: foo + +foo: foomodule$(SO) +foomodule$(SO) : foomodule.o $(OBJS) + $(LD) $(LDFLAGS) -o $@ $< $(OBJS) $(LIBS) + +foomodule.o: foomodule.c + + +$(OBJS) : $(SRCS) +%.o : %.f ; $(FC) -c $(FFLAGS) $< +%.o : %.f90 ; $(FC) -c $(FFLAGS) $< + +test: foomodule$(SO) + python -c 'import foo;print foo.__doc__' +install: foomodule$(SO) + $(INSTALLDIR) $(INSTALLDIRECTORY) + $(INSTALLEXEC) foomodule$(SO) $(INSTALLDIRECTORY) + cd $(INSTALLDIRECTORY) && echo "$(INSTALLNAME)" > ../$(INSTALLNAME).pth + +.PHONY: clean distclean debug test install foo +debug: + echo "OBJS=$(OBJS)" + echo "SRCS=$(SRCS)" +clean: + $(RM) *.o *.mod core foomodule.{dvi,log} $(OBJS) +distclean: clean + $(RM) *.so *.sl foomodule.{tex,so} + $(RM) .f2py_get_compiler_* diff --git a/numpy/f2py/src/test/bar.f b/numpy/f2py/src/test/bar.f new file mode 100644 index 000000000..5354ceaf9 --- /dev/null +++ b/numpy/f2py/src/test/bar.f @@ -0,0 +1,11 @@ + subroutine bar() + integer a + real*8 b,c(3) + common /foodata/ a,b,c + a = 4 + b = 6.7 + c(2) = 3.0 + write(*,*) "bar:a=",a + write(*,*) "bar:b=",b + write(*,*) "bar:c=",c + end diff --git a/numpy/f2py/src/test/foo.f b/numpy/f2py/src/test/foo.f new file mode 100644 index 000000000..5354ceaf9 --- /dev/null +++ b/numpy/f2py/src/test/foo.f @@ -0,0 +1,11 @@ + subroutine bar() + integer a + real*8 b,c(3) + common /foodata/ a,b,c + a = 4 + b = 6.7 + c(2) = 3.0 + write(*,*) "bar:a=",a + write(*,*) "bar:b=",b + write(*,*) "bar:c=",c + end diff --git a/numpy/f2py/src/test/foo90.f90 b/numpy/f2py/src/test/foo90.f90 new file mode 100644 index 000000000..dbca7e95b --- /dev/null +++ b/numpy/f2py/src/test/foo90.f90 @@ -0,0 +1,13 @@ +subroutine foo() + integer a + real*8 b,c(3) + common /foodata/ a,b,c + print*, " F: in foo" + a = 5 + b = 6.3 + c(2) = 9.1 +end subroutine foo + + + + diff --git a/numpy/f2py/src/test/foomodule.c b/numpy/f2py/src/test/foomodule.c new file mode 100644 index 000000000..0a954676e --- /dev/null +++ b/numpy/f2py/src/test/foomodule.c @@ -0,0 +1,143 @@ +/* File: foomodule.c + * Example of FortranObject usage. See also wrap.f foo.f foo90.f90. + * Author: Pearu Peterson <pearu@ioc.ee>. + * http://cens.ioc.ee/projects/f2py2e/ + * $Revision: 1.2 $ + * $Date: 2000/09/17 16:10:27 $ + */ +#ifdef __CPLUSPLUS__ +extern "C" { +#endif + +#include "Python.h" +#include "fortranobject.h" + +static PyObject *foo_error; + +#if defined(NO_APPEND_FORTRAN) +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) F +#else +#define F_FUNC(f,F) f +#endif +#else +#if defined(UPPERCASE_FORTRAN) +#define F_FUNC(f,F) F##_ +#else +#define F_FUNC(f,F) f##_ +#endif +#endif + + /************* foo_bar *************/ + static char doc_foo_bar[] = "\ +Function signature:\n\ + bar()\n\ +"; + static PyObject *foo_bar(PyObject *capi_self, PyObject *capi_args, + PyObject *capi_keywds, void (*f2py_func)()) { + PyObject *capi_buildvalue = NULL; + static char *capi_kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\ + "|:foo.bar",\ + capi_kwlist)) + goto capi_fail; + (*f2py_func)(); + capi_buildvalue = Py_BuildValue(""); + capi_fail: + return capi_buildvalue; + } + /************ mod_init **************/ + static PyObject *mod_init(PyObject *capi_self, PyObject *capi_args, + PyObject *capi_keywds, void (*f2py_func)()) { + PyObject *capi_buildvalue = NULL; + static char *capi_kwlist[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\ + "|:mod.init",\ + capi_kwlist)) + goto capi_fail; + (*f2py_func)(); + capi_buildvalue = Py_BuildValue(""); + capi_fail: + return capi_buildvalue; + } + + /* F90 module */ + static FortranDataDef f2py_mod_def[] = { + {"a",0, {}, PyArray_INT}, + {"b",0, {}, PyArray_DOUBLE}, + {"c",1, {3}, PyArray_DOUBLE}, + {"d",1, {-1}, PyArray_DOUBLE}, + {"init",-1,{},0,NULL,(void *)mod_init}, + {NULL} + }; + static void f2py_setup_mod(char *a,char *b,char *c,void (*d)(),char *init) { + f2py_mod_def[0].data = a; + f2py_mod_def[1].data = b; + f2py_mod_def[2].data = c; + f2py_mod_def[3].func = d; + f2py_mod_def[4].data = init; + } + extern void F_FUNC(f2pyinitmod,F2PYINITMOD)(); + static void f2py_init_mod() { + F_FUNC(f2pyinitmod,F2PYINITMOD)(f2py_setup_mod); + } + + /* COMMON block */ + static FortranDataDef f2py_foodata_def[] = { + {"a",0, {}, PyArray_INT}, + {"b",0, {}, PyArray_DOUBLE}, + {"c",1, {3}, PyArray_DOUBLE}, + {NULL} + }; + static void f2py_setup_foodata(char *a,char *b,char *c) { + f2py_foodata_def[0].data = a; + f2py_foodata_def[1].data = b; + f2py_foodata_def[2].data = c; + } + extern void F_FUNC(f2pyinitfoodata,F2PYINITFOODATA)(); + static void f2py_init_foodata() { + F_FUNC(f2pyinitfoodata,F2PYINITFOODATA)(f2py_setup_foodata); + } + + /* Fortran routines (needs no initialization/setup function) */ + extern void F_FUNC(bar,BAR)(); + extern void F_FUNC(foo,FOO)(); + static FortranDataDef f2py_routines_def[] = { + {"bar",-1, {}, 0, (char *)F_FUNC(bar,BAR),(void *)foo_bar,doc_foo_bar}, + {"foo",-1, {}, 0, (char *)F_FUNC(foo,FOO),(void *)foo_bar,doc_foo_bar}, + {NULL} + }; + +static PyMethodDef foo_module_methods[] = { +/*eof method*/ + {NULL,NULL} +}; + +void initfoo() { + int i; + PyObject *m, *d, *s; + PyTypeObject *t; + PyObject *f; + import_array(); + + m = Py_InitModule("foo", foo_module_methods); + + d = PyModule_GetDict(m); + s = PyString_FromString("This module 'foo' demonstrates the usage of fortranobject."); + PyDict_SetItemString(d, "__doc__", s); + + /* Fortran objects: */ + PyDict_SetItemString(d, "mod", PyFortranObject_New(f2py_mod_def,f2py_init_mod)); + PyDict_SetItemString(d, "foodata", PyFortranObject_New(f2py_foodata_def,f2py_init_foodata)); + for(i=0;f2py_routines_def[i].name!=NULL;i++) + PyDict_SetItemString(d, f2py_routines_def[i].name, + PyFortranObject_NewAsAttr(&f2py_routines_def[i])); + + Py_DECREF(s); + + if (PyErr_Occurred()) + Py_FatalError("can't initialize module foo"); +} +#ifdef __CPLUSCPLUS__ +} +#endif diff --git a/numpy/f2py/src/test/wrap.f b/numpy/f2py/src/test/wrap.f new file mode 100644 index 000000000..9414eb9f6 --- /dev/null +++ b/numpy/f2py/src/test/wrap.f @@ -0,0 +1,70 @@ + subroutine f2py_mod_get_dims(f2py_r,f2py_s,f2py_set,f2py_n) + use mod + external f2py_set + logical f2py_ns + integer f2py_s(*),f2py_r,f2py_i,f2py_j + character*(*) f2py_n + if ("d".eq.f2py_n) then + f2py_ns = .FALSE. + if (allocated(d)) then + do f2py_i=1,f2py_r + if ((size(d,f2py_r-f2py_i+1).ne.f2py_s(f2py_i)).and. + c (f2py_s(f2py_i).ge.0)) then + f2py_ns = .TRUE. + end if + end do + if (f2py_ns) then + deallocate(d) + end if + end if + if (.not.allocated(d)) then + allocate(d(f2py_s(1))) + end if + if (allocated(d)) then + do f2py_i=1,f2py_r + f2py_s(f2py_i) = size(d,f2py_r-f2py_i+1) + end do + call f2py_set(d) + end if + end if + end subroutine f2py_mod_get_dims + subroutine f2py_mod_get_dims_d(r,s,set_data) + use mod, only: d => d + external set_data + logical ns + integer s(*),r,i,j + ns = .FALSE. + if (allocated(d)) then + do i=1,r + if ((size(d,r-i+1).ne.s(i)).and.(s(i).ge.0)) then + ns = .TRUE. + end if + end do + if (ns) then + deallocate(d) + end if + end if + if (.not.allocated(d).and.(s(1).ge.1)) then + allocate(d(s(1))) + end if + if (allocated(d)) then + do i=1,r + s(i) = size(d,r-i+1) + end do + end if + call set_data(d,allocated(d)) + end subroutine f2py_mod_get_dims_d + + subroutine f2pyinitmod(setupfunc) + use mod + external setupfunc,f2py_mod_get_dims_d,init + call setupfunc(a,b,c,f2py_mod_get_dims_d,init) + end subroutine f2pyinitmod + + subroutine f2pyinitfoodata(setupfunc) + external setupfunc + integer a + real*8 b,c(3) + common /foodata/ a,b,c + call setupfunc(a,b,c) + end subroutine f2pyinitfoodata diff --git a/numpy/f2py/tests/array_from_pyobj/__init__.py b/numpy/f2py/tests/array_from_pyobj/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/numpy/f2py/tests/array_from_pyobj/__init__.py diff --git a/numpy/f2py/tests/array_from_pyobj/setup.py b/numpy/f2py/tests/array_from_pyobj/setup.py new file mode 100644 index 000000000..ff7ff8cfc --- /dev/null +++ b/numpy/f2py/tests/array_from_pyobj/setup.py @@ -0,0 +1,26 @@ + +import os +def configuration(parent_name='',top_path=None): + from scipy.distutils.misc_util import Configuration + + config = Configuration('array_from_pyobj',parent_name,top_path) + #import scipy.f2py as f2py + #f2pydir=os.path.dirname(os.path.abspath(f2py.__file__)) + f2pydir=os.path.join(config.local_path,'..','..') + fobjhsrc = os.path.join(f2pydir,'src','fortranobject.h') + fobjcsrc = os.path.join(f2pydir,'src','fortranobject.c') + config.add_extension('wrap', + sources = ['wrapmodule.c',fobjcsrc], + include_dirs = [os.path.dirname(fobjhsrc)], + depends = [fobjhsrc,fobjcsrc], + define_macros = [('DEBUG_COPY_ND_ARRAY',1), + #('F2PY_REPORT_ON_ARRAY_COPY',1), + #('F2PY_REPORT_ATEXIT',1) + ] + ) + + return config + +if __name__ == "__main__": + from scipy.distutils.core import setup + setup(**configuration(top_path='').todict()) diff --git a/numpy/f2py/tests/array_from_pyobj/tests/test_array_from_pyobj.py b/numpy/f2py/tests/array_from_pyobj/tests/test_array_from_pyobj.py new file mode 100644 index 000000000..309ad03f6 --- /dev/null +++ b/numpy/f2py/tests/array_from_pyobj/tests/test_array_from_pyobj.py @@ -0,0 +1,512 @@ +import unittest +import sys +import copy + +from scipy.test.testing import * +from scipy.base import array, typeinfo, alltrue, ndarray, asarray, can_cast,zeros +set_package_path() +from array_from_pyobj import wrap +del sys.path[0] + +def flags_info(arr): + flags = wrap.array_attrs(arr)[6] + return flags2names(flags) + +def flags2names(flags): + info = [] + for flagname in ['CONTIGUOUS','FORTRAN','OWNDATA','ENSURECOPY', + 'ENSUREARRAY','ALIGNED','NOTSWAPPED','WRITEABLE', + 'UPDATEIFCOPY','BEHAVED_FLAGS','BEHAVED_FLAGS_RO', + 'CARRAY_FLAGS','FARRAY_FLAGS' + ]: + if abs(flags) & getattr(wrap,flagname): + info.append(flagname) + return info + +class Intent: + def __init__(self,intent_list=[]): + self.intent_list = intent_list[:] + flags = 0 + for i in intent_list: + if i=='optional': + flags |= wrap.F2PY_OPTIONAL + else: + flags |= getattr(wrap,'F2PY_INTENT_'+i.upper()) + self.flags = flags + def __getattr__(self,name): + name = name.lower() + if name=='in_': name='in' + return self.__class__(self.intent_list+[name]) + def __str__(self): + return 'intent(%s)' % (','.join(self.intent_list)) + def __repr__(self): + return 'Intent(%r)' % (self.intent_list) + def is_intent(self,*names): + for name in names: + if name not in self.intent_list: + return False + return True + def is_intent_exact(self,*names): + return len(self.intent_list)==len(names) and self.is_intent(*names) + +intent = Intent() + +class Type(object): + + _type_names = ['BOOL','BYTE','UBYTE','SHORT','USHORT','INT','UINT', + 'LONG','ULONG','LONGLONG','ULONGLONG', + 'FLOAT','DOUBLE','LONGDOUBLE','CFLOAT','CDOUBLE', + 'CLONGDOUBLE'] + _type_cache = {} + + _cast_dict = {'BOOL':['BOOL']} + _cast_dict['BYTE'] = _cast_dict['BOOL'] + ['BYTE'] + _cast_dict['UBYTE'] = _cast_dict['BOOL'] + ['UBYTE'] + _cast_dict['BYTE'] = ['BYTE'] + _cast_dict['UBYTE'] = ['UBYTE'] + _cast_dict['SHORT'] = _cast_dict['BYTE'] + ['UBYTE','SHORT'] + _cast_dict['USHORT'] = _cast_dict['UBYTE'] + ['BYTE','USHORT'] + _cast_dict['INT'] = _cast_dict['SHORT'] + ['USHORT','INT'] + _cast_dict['UINT'] = _cast_dict['USHORT'] + ['SHORT','UINT'] + + _cast_dict['LONG'] = _cast_dict['INT'] + ['LONG'] + _cast_dict['ULONG'] = _cast_dict['UINT'] + ['ULONG'] + + _cast_dict['LONGLONG'] = _cast_dict['LONG'] + ['LONGLONG'] + _cast_dict['ULONGLONG'] = _cast_dict['ULONG'] + ['ULONGLONG'] + + _cast_dict['FLOAT'] = _cast_dict['SHORT'] + ['USHORT','FLOAT'] + _cast_dict['DOUBLE'] = _cast_dict['INT'] + ['UINT','FLOAT','DOUBLE'] + _cast_dict['LONGDOUBLE'] = _cast_dict['LONG'] + ['ULONG','FLOAT','DOUBLE','LONGDOUBLE'] + + _cast_dict['CFLOAT'] = _cast_dict['FLOAT'] + ['CFLOAT'] + _cast_dict['CDOUBLE'] = _cast_dict['DOUBLE'] + ['CFLOAT','CDOUBLE'] + _cast_dict['CLONGDOUBLE'] = _cast_dict['LONGDOUBLE'] + ['CFLOAT','CDOUBLE','CLONGDOUBLE'] + + + def __new__(cls,name): + if isinstance(name,type): + dtype = name + name = None + for n,i in typeinfo.items(): + if isinstance(i,tuple) and dtype is i[-1]: + name = n + break + obj = cls._type_cache.get(name.upper(),None) + if obj is not None: + return obj + obj = object.__new__(cls) + obj._init(name) + cls._type_cache[name.upper()] = obj + return obj + + def _init(self,name): + self.NAME = name.upper() + self.type_num = getattr(wrap,'PyArray_'+self.NAME) + assert_equal(self.type_num,typeinfo[self.NAME][1]) + self.dtype = typeinfo[self.NAME][-1] + self.elsize = typeinfo[self.NAME][2] / 8 + self.dtypechar = typeinfo[self.NAME][0] + + def cast_types(self): + return map(self.__class__,self._cast_dict[self.NAME]) + + def all_types(self): + return map(self.__class__,self._type_names) + + def smaller_types(self): + bits = typeinfo[self.NAME][3] + types = [] + for name in self._type_names: + if typeinfo[name][3]<bits: + types.append(Type(name)) + return types + + def equal_types(self): + bits = typeinfo[self.NAME][3] + types = [] + for name in self._type_names: + if name==self.NAME: continue + if typeinfo[name][3]==bits: + types.append(Type(name)) + return types + + def larger_types(self): + bits = typeinfo[self.NAME][3] + types = [] + for name in self._type_names: + if typeinfo[name][3]>bits: + types.append(Type(name)) + return types + +class Array: + def __init__(self,typ,dims,intent,obj): + self.type = typ + self.dims = dims + self.intent = intent + self.obj_copy = copy.deepcopy(obj) + self.obj = obj + + # arr.dtypechar may be different from typ.dtypechar + self.arr = wrap.call(typ.type_num,dims,intent.flags,obj) + + self.arr_attr = wrap.array_attrs(self.arr) + + if len(dims)>1: + if self.intent.is_intent('c'): + assert intent.flags & wrap.F2PY_INTENT_C + assert not self.arr.flags['FORTRAN'],`self.arr.flags,obj.flags` + assert self.arr.flags['CONTIGUOUS'] + assert not self.arr_attr[6] & wrap.FORTRAN + else: + assert not intent.flags & wrap.F2PY_INTENT_C + assert self.arr.flags['FORTRAN'] + assert not self.arr.flags['CONTIGUOUS'] + assert self.arr_attr[6] & wrap.FORTRAN + + if obj is None: + self.pyarr = None + self.pyarr_attr = None + return + + if intent.is_intent('cache'): + assert isinstance(obj,ndarray),`type(obj)` + self.pyarr = array(obj).reshape(*dims) + + else: + self.pyarr = array(array(obj, + dtype = typ.dtypechar).reshape(*dims), + fortran=not self.intent.is_intent('c')) + assert self.pyarr.dtypechar==typ.dtypechar,\ + `self.pyarr.dtypechar,typ.dtypechar` + assert self.pyarr.flags['OWNDATA'] + self.pyarr_attr = wrap.array_attrs(self.pyarr) + + if len(dims)>1: + if self.intent.is_intent('c'): + assert not self.pyarr.flags['FORTRAN'] + assert self.pyarr.flags['CONTIGUOUS'] + assert not self.pyarr_attr[6] & wrap.FORTRAN + else: + assert self.pyarr.flags['FORTRAN'] + assert not self.pyarr.flags['CONTIGUOUS'] + assert self.pyarr_attr[6] & wrap.FORTRAN + + + assert self.arr_attr[1]==self.pyarr_attr[1] # nd + assert self.arr_attr[2]==self.pyarr_attr[2] # dimensions + if self.arr_attr[1]<=1: + assert self.arr_attr[3]==self.pyarr_attr[3],\ + `self.arr_attr[3],self.pyarr_attr[3],self.arr.tostring(),self.pyarr.tostring()` # strides + assert self.arr_attr[5][-2:]==self.pyarr_attr[5][-2:],\ + `self.arr_attr[5],self.pyarr_attr[5]` # descr + assert self.arr_attr[6]==self.pyarr_attr[6],\ + `self.arr_attr[6],self.pyarr_attr[6],flags2names(0*self.arr_attr[6]-self.pyarr_attr[6]),flags2names(self.arr_attr[6]),intent` # flags + + if intent.is_intent('cache'): + assert self.arr_attr[5][3]>=self.type.elsize,\ + `self.arr_attr[5][3],self.type.elsize` + else: + assert self.arr_attr[5][3]==self.type.elsize,\ + `self.arr_attr[5][3],self.type.elsize` + assert self.arr_equal(self.pyarr,self.arr) + + if isinstance(self.obj,ndarray): + if typ.elsize==Type(obj.dtype).elsize: + if not intent.is_intent('copy') and self.arr_attr[1]<=1: + assert self.has_shared_memory() + + def arr_equal(self,arr1,arr2): + if arr1.shape != arr2.shape: + return False + return alltrue(arr1==arr2) + + def __str__(self): + return str(self.arr) + + def has_shared_memory(self): + """Check that created array shares data with input array. + """ + if self.obj is self.arr: + return True + if not isinstance(self.obj,ndarray): + return False + obj_attr = wrap.array_attrs(self.obj) + return obj_attr[0]==self.arr_attr[0] + +################################################## + +class test_intent(unittest.TestCase): + def check_in_out(self): + assert_equal(str(intent.in_.out),'intent(in,out)') + assert intent.in_.c.is_intent('c') + assert not intent.in_.c.is_intent_exact('c') + assert intent.in_.c.is_intent_exact('c','in') + assert intent.in_.c.is_intent_exact('in','c') + assert not intent.in_.is_intent('c') + +class _test_shared_memory: + num2seq = [1,2] + num23seq = [[1,2,3],[4,5,6]] + def check_in_from_2seq(self): + a = self.array([2],intent.in_,self.num2seq) + assert not a.has_shared_memory() + + def check_in_from_2casttype(self): + for t in self.type.cast_types(): + obj = array(self.num2seq,dtype=t.dtype) + a = self.array([len(self.num2seq)],intent.in_,obj) + if t.elsize==self.type.elsize: + assert a.has_shared_memory(),`self.type.dtype,t.dtype` + else: + assert not a.has_shared_memory(),`t.dtype` + + def check_inout_2seq(self): + obj = array(self.num2seq,dtype=self.type.dtype) + a = self.array([len(self.num2seq)],intent.inout,obj) + assert a.has_shared_memory() + + try: + a = self.array([2],intent.in_.inout,self.num2seq) + except TypeError,msg: + if not str(msg).startswith('failed to initialize intent(inout|inplace|cache) array'): + raise + else: + raise SystemError,'intent(inout) should have failed on sequence' + + def check_f_inout_23seq(self): + obj = array(self.num23seq,dtype=self.type.dtype,fortran=1) + shape = (len(self.num23seq),len(self.num23seq[0])) + a = self.array(shape,intent.in_.inout,obj) + assert a.has_shared_memory() + + obj = array(self.num23seq,dtype=self.type.dtype,fortran=0) + shape = (len(self.num23seq),len(self.num23seq[0])) + try: + a = self.array(shape,intent.in_.inout,obj) + except ValueError,msg: + if not str(msg).startswith('failed to initialize intent(inout) array'): + raise + else: + raise SystemError,'intent(inout) should have failed on improper array' + + def check_c_inout_23seq(self): + obj = array(self.num23seq,dtype=self.type.dtype) + shape = (len(self.num23seq),len(self.num23seq[0])) + a = self.array(shape,intent.in_.c.inout,obj) + assert a.has_shared_memory() + + def check_in_copy_from_2casttype(self): + for t in self.type.cast_types(): + obj = array(self.num2seq,dtype=t.dtype) + a = self.array([len(self.num2seq)],intent.in_.copy,obj) + assert not a.has_shared_memory(),`t.dtype` + + def check_c_in_from_23seq(self): + a = self.array([len(self.num23seq),len(self.num23seq[0])], + intent.in_,self.num23seq) + assert not a.has_shared_memory() + + def check_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq,dtype=t.dtype) + a = self.array([len(self.num23seq),len(self.num23seq[0])], + intent.in_,obj) + assert not a.has_shared_memory(),`t.dtype` + + def check_f_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq,dtype=t.dtype,fortran=1) + a = self.array([len(self.num23seq),len(self.num23seq[0])], + intent.in_,obj) + if t.elsize==self.type.elsize: + assert a.has_shared_memory(),`t.dtype` + else: + assert not a.has_shared_memory(),`t.dtype` + + def check_c_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq,dtype=t.dtype) + a = self.array([len(self.num23seq),len(self.num23seq[0])], + intent.in_.c,obj) + if t.elsize==self.type.elsize: + assert a.has_shared_memory(),`t.dtype` + else: + assert not a.has_shared_memory(),`t.dtype` + + def check_f_copy_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq,dtype=t.dtype,fortran=1) + a = self.array([len(self.num23seq),len(self.num23seq[0])], + intent.in_.copy,obj) + assert not a.has_shared_memory(),`t.dtype` + + def check_c_copy_in_from_23casttype(self): + for t in self.type.cast_types(): + obj = array(self.num23seq,dtype=t.dtype) + a = self.array([len(self.num23seq),len(self.num23seq[0])], + intent.in_.c.copy,obj) + assert not a.has_shared_memory(),`t.dtype` + + def check_in_cache_from_2casttype(self): + for t in self.type.all_types(): + if t.elsize != self.type.elsize: + continue + obj = array(self.num2seq,dtype=t.dtype) + shape = (len(self.num2seq),) + a = self.array(shape,intent.in_.c.cache,obj) + assert a.has_shared_memory(),`t.dtype` + + a = self.array(shape,intent.in_.cache,obj) + assert a.has_shared_memory(),`t.dtype` + + obj = array(self.num2seq,dtype=t.dtype,fortran=1) + a = self.array(shape,intent.in_.c.cache,obj) + assert a.has_shared_memory(),`t.dtype` + + a = self.array(shape,intent.in_.cache,obj) + assert a.has_shared_memory(),`t.dtype` + + try: + a = self.array(shape,intent.in_.cache,obj[::-1]) + except ValueError,msg: + if not str(msg).startswith('failed to initialize intent(cache) array'): + raise + else: + raise SystemError,'intent(cache) should have failed on multisegmented array' + def check_in_cache_from_2casttype_failure(self): + for t in self.type.all_types(): + if t.elsize >= self.type.elsize: + continue + obj = array(self.num2seq,dtype=t.dtype) + shape = (len(self.num2seq),) + try: + a = self.array(shape,intent.in_.cache,obj) + except ValueError,msg: + if not str(msg).startswith('failed to initialize intent(cache) array'): + raise + else: + raise SystemError,'intent(cache) should have failed on smaller array' + + def check_cache_hidden(self): + shape = (2,) + a = self.array(shape,intent.cache.hide,None) + assert a.arr.shape==shape + + shape = (2,3) + a = self.array(shape,intent.cache.hide,None) + assert a.arr.shape==shape + + shape = (-1,3) + try: + a = self.array(shape,intent.cache.hide,None) + except ValueError,msg: + if not str(msg).startswith('failed to create intent(cache|hide)|optional array'): + raise + else: + raise SystemError,'intent(cache) should have failed on undefined dimensions' + + def check_hidden(self): + shape = (2,) + a = self.array(shape,intent.hide,None) + assert a.arr.shape==shape + assert a.arr_equal(a.arr,zeros(shape,dtype=self.type.dtype)) + + shape = (2,3) + a = self.array(shape,intent.hide,None) + assert a.arr.shape==shape + assert a.arr_equal(a.arr,zeros(shape,dtype=self.type.dtype)) + assert a.arr.flags['FORTRAN'] and not a.arr.flags['CONTIGUOUS'] + + shape = (2,3) + a = self.array(shape,intent.c.hide,None) + assert a.arr.shape==shape + assert a.arr_equal(a.arr,zeros(shape,dtype=self.type.dtype)) + assert not a.arr.flags['FORTRAN'] and a.arr.flags['CONTIGUOUS'] + + shape = (-1,3) + try: + a = self.array(shape,intent.hide,None) + except ValueError,msg: + if not str(msg).startswith('failed to create intent(cache|hide)|optional array'): + raise + else: + raise SystemError,'intent(hide) should have failed on undefined dimensions' + + def check_optional_none(self): + shape = (2,) + a = self.array(shape,intent.optional,None) + assert a.arr.shape==shape + assert a.arr_equal(a.arr,zeros(shape,dtype=self.type.dtype)) + + shape = (2,3) + a = self.array(shape,intent.optional,None) + assert a.arr.shape==shape + assert a.arr_equal(a.arr,zeros(shape,dtype=self.type.dtype)) + assert a.arr.flags['FORTRAN'] and not a.arr.flags['CONTIGUOUS'] + + shape = (2,3) + a = self.array(shape,intent.c.optional,None) + assert a.arr.shape==shape + assert a.arr_equal(a.arr,zeros(shape,dtype=self.type.dtype)) + assert not a.arr.flags['FORTRAN'] and a.arr.flags['CONTIGUOUS'] + + def check_optional_from_2seq(self): + obj = self.num2seq + shape = (len(obj),) + a = self.array(shape,intent.optional,obj) + assert a.arr.shape==shape + assert not a.has_shared_memory() + + def check_optional_from_23seq(self): + obj = self.num23seq + shape = (len(obj),len(obj[0])) + a = self.array(shape,intent.optional,obj) + assert a.arr.shape==shape + assert not a.has_shared_memory() + + a = self.array(shape,intent.optional.c,obj) + assert a.arr.shape==shape + assert not a.has_shared_memory() + + def check_inplace(self): + obj = array(self.num23seq,dtype=self.type.dtype) + assert not obj.flags['FORTRAN'] and obj.flags['CONTIGUOUS'] + shape = obj.shape + a = self.array(shape,intent.inplace,obj) + assert obj[1][2]==a.arr[1][2],`obj,a.arr` + a.arr[1][2]=54 + assert obj[1][2]==a.arr[1][2]==array(54,dtype=self.type.dtype),`obj,a.arr` + assert a.arr is obj + assert obj.flags['FORTRAN'] # obj attributes are changed inplace! + assert not obj.flags['CONTIGUOUS'] + + def check_inplace_from_casttype(self): + for t in self.type.cast_types(): + if t is self.type: + continue + obj = array(self.num23seq,dtype=t.dtype) + assert obj.dtype==t.dtype + assert obj.dtype is not self.type.dtype + assert not obj.flags['FORTRAN'] and obj.flags['CONTIGUOUS'] + shape = obj.shape + a = self.array(shape,intent.inplace,obj) + assert obj[1][2]==a.arr[1][2],`obj,a.arr` + a.arr[1][2]=54 + assert obj[1][2]==a.arr[1][2]==array(54,dtype=self.type.dtype),`obj,a.arr` + assert a.arr is obj + assert obj.flags['FORTRAN'] # obj attributes are changed inplace! + assert not obj.flags['CONTIGUOUS'] + assert obj.dtype is self.type.dtype # obj type is changed inplace! + +for t in Type._type_names: + exec '''\ +class test_%s_gen(unittest.TestCase, + _test_shared_memory + ): + type = Type(%r) + array = lambda self,dims,intent,obj: Array(Type(%r),dims,intent,obj) +''' % (t,t,t) + +if __name__ == "__main__": + ScipyTest().run() diff --git a/numpy/f2py/tests/array_from_pyobj/wrapmodule.c b/numpy/f2py/tests/array_from_pyobj/wrapmodule.c new file mode 100644 index 000000000..0d9e41f1c --- /dev/null +++ b/numpy/f2py/tests/array_from_pyobj/wrapmodule.c @@ -0,0 +1,194 @@ +/* File: wrapmodule.c + * This file is auto-generated with f2py (version:2_1330). + * Hand edited by Pearu. + * f2py is a Fortran to Python Interface Generator (FPIG), Second Edition, + * written by Pearu Peterson <pearu@cens.ioc.ee>. + * See http://cens.ioc.ee/projects/f2py2e/ + * Generation date: Fri Oct 21 22:41:12 2005 + * $Revision:$ + * $Date:$ + * Do not edit this file directly unless you know what you are doing!!! + */ +#ifdef __cplusplus +extern "C" { +#endif + +/*********************** See f2py2e/cfuncs.py: includes ***********************/ +#include "Python.h" +#include "fortranobject.h" +#include <math.h> + +static PyObject *wrap_error; +static PyObject *wrap_module; + +/************************************ call ************************************/ +static char doc_f2py_rout_wrap_call[] = "\ +Function signature:\n\ + arr = call(type_num,dims,intent,obj)\n\ +Required arguments:\n" +" type_num : input int\n" +" dims : input int-sequence\n" +" intent : input int\n" +" obj : input python object\n" +"Return objects:\n" +" arr : array"; +static PyObject *f2py_rout_wrap_call(PyObject *capi_self, + PyObject *capi_args) { + PyObject * volatile capi_buildvalue = NULL; + int type_num = 0; + intp *dims = NULL; + PyObject *dims_capi = Py_None; + int rank = 0; + int intent = 0; + PyArrayObject *capi_arr_tmp = NULL; + PyObject *arr_capi = Py_None; + int i; + + if (!PyArg_ParseTuple(capi_args,"iOiO|:wrap.call",\ + &type_num,&dims_capi,&intent,&arr_capi)) + return NULL; + rank = PySequence_Length(dims_capi); + dims = malloc(rank*sizeof(intp)); + for (i=0;i<rank;++i) + dims[i] = (intp)PyInt_AsLong(PySequence_GetItem(dims_capi,i)); + + capi_arr_tmp = array_from_pyobj(type_num,dims,rank,intent|F2PY_INTENT_OUT,arr_capi); + if (capi_arr_tmp == NULL) + return NULL; + capi_buildvalue = Py_BuildValue("N",capi_arr_tmp); + free(dims); + return capi_buildvalue; +} + +static char doc_f2py_rout_wrap_attrs[] = "\ +Function signature:\n\ + arr = array_attrs(arr)\n\ +Required arguments:\n" +" arr : input array object\n" +"Return objects:\n" +" data : data address in hex\n" +" nd : int\n" +" dimensions : tuple\n" +" strides : tuple\n" +" base : python object\n" +" (kind,type,type_num,elsize,alignment) : 4-tuple\n" +" flags : int\n" +" itemsize : int\n" +; +static PyObject *f2py_rout_wrap_attrs(PyObject *capi_self, + PyObject *capi_args) { + PyObject *arr_capi = Py_None; + PyArrayObject *arr = NULL; + PyObject *dimensions = NULL; + PyObject *strides = NULL; + char s[100]; + int i; + memset(s,0,100*sizeof(char)); + if (!PyArg_ParseTuple(capi_args,"O!|:wrap.attrs", + &PyArray_Type,&arr_capi)) + return NULL; + arr = (PyArrayObject *)arr_capi; + sprintf(s,"%p",arr->data); + dimensions = PyTuple_New(arr->nd); + strides = PyTuple_New(arr->nd); + for (i=0;i<arr->nd;++i) { + PyTuple_SetItem(dimensions,i,PyInt_FromLong(arr->dimensions[i])); + PyTuple_SetItem(strides,i,PyInt_FromLong(arr->strides[i])); + } + return Py_BuildValue("siOOO(cciii)ii",s,arr->nd, + dimensions,strides, + (arr->base==NULL?Py_None:arr->base), + arr->descr->kind, + arr->descr->type, + arr->descr->type_num, + arr->descr->elsize, + arr->descr->alignment, + arr->flags, + arr->itemsize); +} + +static PyMethodDef f2py_module_methods[] = { + + {"call",f2py_rout_wrap_call,METH_VARARGS,doc_f2py_rout_wrap_call}, + {"array_attrs",f2py_rout_wrap_attrs,METH_VARARGS,doc_f2py_rout_wrap_attrs}, + {NULL,NULL} +}; + +DL_EXPORT(void) initwrap(void) { + PyObject *m,*d, *s; + m = wrap_module = Py_InitModule("wrap", f2py_module_methods); + PyFortran_Type.ob_type = &PyType_Type; + import_array(); + if (PyErr_Occurred()) + Py_FatalError("can't initialize module wrap (failed to import scipy.base)"); + d = PyModule_GetDict(m); + s = PyString_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n" +" arr = call(type_num,dims,intent,obj)\n" +"."); + PyDict_SetItemString(d, "__doc__", s); + wrap_error = PyErr_NewException ("wrap.error", NULL, NULL); + Py_DECREF(s); + PyDict_SetItemString(d, "F2PY_INTENT_IN", PyInt_FromLong(F2PY_INTENT_IN)); + PyDict_SetItemString(d, "F2PY_INTENT_INOUT", PyInt_FromLong(F2PY_INTENT_INOUT)); + PyDict_SetItemString(d, "F2PY_INTENT_OUT", PyInt_FromLong(F2PY_INTENT_OUT)); + PyDict_SetItemString(d, "F2PY_INTENT_HIDE", PyInt_FromLong(F2PY_INTENT_HIDE)); + PyDict_SetItemString(d, "F2PY_INTENT_CACHE", PyInt_FromLong(F2PY_INTENT_CACHE)); + PyDict_SetItemString(d, "F2PY_INTENT_COPY", PyInt_FromLong(F2PY_INTENT_COPY)); + PyDict_SetItemString(d, "F2PY_INTENT_C", PyInt_FromLong(F2PY_INTENT_C)); + PyDict_SetItemString(d, "F2PY_OPTIONAL", PyInt_FromLong(F2PY_OPTIONAL)); + PyDict_SetItemString(d, "F2PY_INTENT_INPLACE", PyInt_FromLong(F2PY_INTENT_INPLACE)); + PyDict_SetItemString(d, "PyArray_BOOL", PyInt_FromLong(PyArray_BOOL)); + PyDict_SetItemString(d, "PyArray_BYTE", PyInt_FromLong(PyArray_BYTE)); + PyDict_SetItemString(d, "PyArray_UBYTE", PyInt_FromLong(PyArray_UBYTE)); + PyDict_SetItemString(d, "PyArray_SHORT", PyInt_FromLong(PyArray_SHORT)); + PyDict_SetItemString(d, "PyArray_USHORT", PyInt_FromLong(PyArray_USHORT)); + PyDict_SetItemString(d, "PyArray_INT", PyInt_FromLong(PyArray_INT)); + PyDict_SetItemString(d, "PyArray_UINT", PyInt_FromLong(PyArray_UINT)); + PyDict_SetItemString(d, "PyArray_INTP", PyInt_FromLong(PyArray_INTP)); + PyDict_SetItemString(d, "PyArray_UINTP", PyInt_FromLong(PyArray_UINTP)); + PyDict_SetItemString(d, "PyArray_LONG", PyInt_FromLong(PyArray_LONG)); + PyDict_SetItemString(d, "PyArray_ULONG", PyInt_FromLong(PyArray_ULONG)); + PyDict_SetItemString(d, "PyArray_LONGLONG", PyInt_FromLong(PyArray_LONGLONG)); + PyDict_SetItemString(d, "PyArray_ULONGLONG", PyInt_FromLong(PyArray_ULONGLONG)); + PyDict_SetItemString(d, "PyArray_FLOAT", PyInt_FromLong(PyArray_FLOAT)); + PyDict_SetItemString(d, "PyArray_DOUBLE", PyInt_FromLong(PyArray_DOUBLE)); + PyDict_SetItemString(d, "PyArray_LONGDOUBLE", PyInt_FromLong(PyArray_LONGDOUBLE)); + PyDict_SetItemString(d, "PyArray_CFLOAT", PyInt_FromLong(PyArray_CFLOAT)); + PyDict_SetItemString(d, "PyArray_CDOUBLE", PyInt_FromLong(PyArray_CDOUBLE)); + PyDict_SetItemString(d, "PyArray_CLONGDOUBLE", PyInt_FromLong(PyArray_CLONGDOUBLE)); + PyDict_SetItemString(d, "PyArray_OBJECT", PyInt_FromLong(PyArray_OBJECT)); + PyDict_SetItemString(d, "PyArray_STRING", PyInt_FromLong(PyArray_STRING)); + PyDict_SetItemString(d, "PyArray_UNICODE", PyInt_FromLong(PyArray_UNICODE)); + PyDict_SetItemString(d, "PyArray_VOID", PyInt_FromLong(PyArray_VOID)); + PyDict_SetItemString(d, "PyArray_NTYPES", PyInt_FromLong(PyArray_NTYPES)); + PyDict_SetItemString(d, "PyArray_NOTYPE", PyInt_FromLong(PyArray_NOTYPE)); + PyDict_SetItemString(d, "PyArray_UDERDEF", PyInt_FromLong(PyArray_USERDEF)); + + PyDict_SetItemString(d, "CONTIGUOUS", PyInt_FromLong(CONTIGUOUS)); + PyDict_SetItemString(d, "FORTRAN", PyInt_FromLong(FORTRAN)); + PyDict_SetItemString(d, "OWNDATA", PyInt_FromLong(OWNDATA)); + PyDict_SetItemString(d, "ENSURECOPY", PyInt_FromLong(ENSURECOPY)); + PyDict_SetItemString(d, "ENSUREARRAY", PyInt_FromLong(ENSUREARRAY)); + PyDict_SetItemString(d, "ALIGNED", PyInt_FromLong(ALIGNED)); + PyDict_SetItemString(d, "NOTSWAPPED", PyInt_FromLong(NOTSWAPPED)); + PyDict_SetItemString(d, "WRITEABLE", PyInt_FromLong(WRITEABLE)); + PyDict_SetItemString(d, "UPDATEIFCOPY", PyInt_FromLong(UPDATEIFCOPY)); + + PyDict_SetItemString(d, "BEHAVED_FLAGS", PyInt_FromLong(BEHAVED_FLAGS)); + PyDict_SetItemString(d, "BEHAVED_FLAGS_RO", PyInt_FromLong(BEHAVED_FLAGS_RO)); + PyDict_SetItemString(d, "CARRAY_FLAGS", PyInt_FromLong(CARRAY_FLAGS)); + PyDict_SetItemString(d, "FARRAY_FLAGS", PyInt_FromLong(FARRAY_FLAGS)); + PyDict_SetItemString(d, "DEFAULT_FLAGS", PyInt_FromLong(DEFAULT_FLAGS)); + PyDict_SetItemString(d, "UPDATE_ALL_FLAGS", PyInt_FromLong(UPDATE_ALL_FLAGS)); + + if (PyErr_Occurred()) + Py_FatalError("can't initialize module wrap"); + +#ifdef F2PY_REPORT_ATEXIT + on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call"); +#endif + +} +#ifdef __cplusplus +} +#endif diff --git a/numpy/f2py/tests/c/return_real.py b/numpy/f2py/tests/c/return_real.py new file mode 100644 index 000000000..7d35b28cf --- /dev/null +++ b/numpy/f2py/tests/c/return_real.py @@ -0,0 +1,108 @@ +__usage__ = """ +Run: + python return_real.py [<f2py options>] +Examples: + python return_real.py --fcompiler=Gnu --no-wrap-functions + python return_real.py --quiet +""" + + +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import c_ext_return_real + except ImportError: + assert not f2py2e.compile('''\ +python module c_ext_return_real +usercode \'\'\' +float t4(float value) { return value; } +void s4(float *t4, float value) { *t4 = value; } +double t8(double value) { return value; } +void s8(double *t8, double value) { *t8 = value; } +\'\'\' +interface + function t4(value) + real*4 intent(c) :: t4,value + end + function t8(value) + real*8 intent(c) :: t8,value + end + subroutine s4(t4,value) + intent(c) s4 + real*4 intent(out) :: t4 + real*4 intent(c) :: value + end + subroutine s8(t8,value) + intent(c) s8 + real*8 intent(out) :: t8 + real*8 intent(c) :: value + end +end interface +end python module c_ext_return_real +''','c_ext_return_real',f2py_opts,source_fn='c_ret_real.pyf') + + from c_ext_return_real import t4,t8,s4,s8 + test_functions = [t4,t8,s4,s8] + return test_functions + +def runtest(t): + import sys + if t.__doc__.split()[0] in ['t0','t4','s0','s4']: + err = 1e-5 + else: + err = 0.0 + assert abs(t(234)-234.0)<=err + assert abs(t(234.6)-234.6)<=err + assert abs(t(234l)-234.0)<=err + if sys.version[:3]<'2.3': + assert abs(t(234.6+3j)-234.6)<=err + assert abs(t('234')-234)<=err + assert abs(t('234.6')-234.6)<=err + assert abs(t(-234)+234)<=err + assert abs(t([234])-234)<=err + assert abs(t((234,))-234.)<=err + assert abs(t(array(234))-234.)<=err + assert abs(t(array([234]))-234.)<=err + assert abs(t(array([[234]]))-234.)<=err + assert abs(t(array([234],'1'))+22)<=err + assert abs(t(array([234],'s'))-234.)<=err + assert abs(t(array([234],'i'))-234.)<=err + assert abs(t(array([234],'l'))-234.)<=err + assert abs(t(array([234],'b'))-234.)<=err + assert abs(t(array([234],'f'))-234.)<=err + assert abs(t(array([234],'d'))-234.)<=err + if sys.version[:3]<'2.3': + assert abs(t(array([234+3j],'F'))-234.)<=err + assert abs(t(array([234],'D'))-234.)<=err + if t.__doc__.split()[0] in ['t0','t4','s0','s4']: + assert t(1e200)==t(1e300) # inf + + try: raise RuntimeError,`t(array([234],'c'))` + except ValueError: pass + try: raise RuntimeError,`t('abc')` + except ValueError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + try: + try: raise RuntimeError,`t(10l**400)` + except OverflowError: pass + except RuntimeError: + r = t(10l**400); assert `r` in ['inf','Infinity'],`r` + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/f77/callback.py b/numpy/f2py/tests/f77/callback.py new file mode 100644 index 000000000..672504bc7 --- /dev/null +++ b/numpy/f2py/tests/f77/callback.py @@ -0,0 +1,99 @@ + +__usage__ = """ +Run: + python callback.py [<f2py options>] +Examples: + python callback.py --fcompiler=Gnu --no-wrap-functions + python callback.py --quiet +""" + +import f2py2e +import math +import sys +from Numeric import array + +def build(f2py_opts): + try: + import f77_ext_callback + except ImportError: + assert not f2py2e.compile('''\ + subroutine t(fun,a) + integer a +cf2py intent(out) a + external fun + call fun(a) + end + + subroutine func(a) +cf2py intent(in,out) a + integer a + a = a + 11 + end + + subroutine func0(a) +cf2py intent(out) a + integer a + a = 11 + end + + subroutine t2(a) +cf2py intent(callback) fun + integer a +cf2py intent(out) a + external fun + call fun(a) + end + +''','f77_ext_callback',f2py_opts,source_fn='f77_callback.f') + + from f77_ext_callback import t,t2 + test_functions = [t,t2] + return test_functions + +def runtest(t): + r = t(lambda : 4) + assert r==4,`r` + r = t(lambda a:5,fun_extra_args=(6,)) + assert r==5,`r` + r = t(lambda a:a,fun_extra_args=(6,)) + assert r==6,`r` + r = t(lambda a:5+a,fun_extra_args=(7,)) + assert r==12,`r` + if sys.version[:3]>='2.3': + r = t(lambda a:math.degrees(a),fun_extra_args=(math.pi,)) + assert r==180,`r` + r = t(math.degrees,fun_extra_args=(math.pi,)) + assert r==180,`r` + from f77_ext_callback import func,func0 + r = t(func,fun_extra_args=(6,)) + assert r==17,`r` + r = t(func0) + assert r==11,`r` + r = t(func0._cpointer) + assert r==11,`r` + class A: + def __call__(self): + return 7 + def mth(self): + return 9 + a = A() + r = t(a) + assert r==7,`r` + r = t(a.mth) + assert r==9,`r` + +if __name__=='__main__': + #import libwadpy + status = 1 + try: + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' + status = 0 + finally: + if status: + print '*'*20 + print 'Running f2py2e.diagnose' + import f2py2e.diagnose + f2py2e.diagnose.run() diff --git a/numpy/f2py/tests/f77/return_character.py b/numpy/f2py/tests/f77/return_character.py new file mode 100644 index 000000000..3361c11f5 --- /dev/null +++ b/numpy/f2py/tests/f77/return_character.py @@ -0,0 +1,100 @@ + +__usage__ = """ +Run: + python return_character.py [<f2py options>] +Examples: + python return_character.py --fcompiler=Gnu --no-wrap-functions + python return_character.py --quiet +""" + +import sys +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import f77_ext_return_character + except ImportError: + assert not f2py2e.compile('''\ + function t0(value) + character value + character t0 + t0 = value + end + function t1(value) + character*1 value + character*1 t1 + t1 = value + end + function t5(value) + character*5 value + character*5 t5 + t5 = value + end + function ts(value) + character*(*) value + character*(*) ts + ts = value + end + + subroutine s0(t0,value) + character value + character t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s1(t1,value) + character*1 value + character*1 t1 +cf2py intent(out) t1 + t1 = value + end + subroutine s5(t5,value) + character*5 value + character*5 t5 +cf2py intent(out) t5 + t5 = value + end + subroutine ss(ts,value) + character*(*) value + character*10 ts +cf2py intent(out) ts + ts = value + end +''','f77_ext_return_character',f2py_opts,source_fn='f77_ret_char.f') + + from f77_ext_return_character import t0,t1,t5,s0,s1,s5,ss + test_functions = [t0,t1,t5,s0,s1,s5,ss] + if sys.platform!='win32': # this is acctually compiler dependent case + from f77_ext_return_character import ts + test_functions.append(ts) + + return test_functions + +def runtest(t): + tname = t.__doc__.split()[0] + if tname in ['t0','t1','s0','s1']: + assert t(23)=='2' + r = t('ab');assert r=='a',`r` + r = t(array('ab'));assert r=='a',`r` + r = t(array(77,'1'));assert r=='M',`r` + try: raise RuntimeError,`t(array([77,87]))` + except ValueError: pass + try: raise RuntimeError,`t(array(77))` + except ValueError: pass + elif tname in ['ts','ss']: + assert t(23)=='23 ',`t(23)` + assert t('123456789abcdef')=='123456789a' + elif tname in ['t5','s5']: + assert t(23)=='23 ',`t(23)` + assert t('ab')=='ab ',`t('ab')` + assert t('123456789abcdef')=='12345' + else: + raise NotImplementedError + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/f77/return_complex.py b/numpy/f2py/tests/f77/return_complex.py new file mode 100644 index 000000000..39743a9f6 --- /dev/null +++ b/numpy/f2py/tests/f77/return_complex.py @@ -0,0 +1,125 @@ +__usage__ = """ +Run: + python return_complex.py [<f2py options>] +Examples: + python return_complex.py --fcompiler=Gnu --no-wrap-functions + python return_complex.py --quiet +""" + + +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import f77_ext_return_complex + except ImportError: + assert not f2py2e.compile('''\ + function t0(value) + complex value + complex t0 + t0 = value + end + function t8(value) + complex*8 value + complex*8 t8 + t8 = value + end + function t16(value) + complex*16 value + complex*16 t16 + t16 = value + end + function td(value) + double complex value + double complex td + td = value + end + + subroutine s0(t0,value) + complex value + complex t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s8(t8,value) + complex*8 value + complex*8 t8 +cf2py intent(out) t8 + t8 = value + end + subroutine s16(t16,value) + complex*16 value + complex*16 t16 +cf2py intent(out) t16 + t16 = value + end + subroutine sd(td,value) + double complex value + double complex td +cf2py intent(out) td + td = value + end +''','f77_ext_return_complex',f2py_opts) + + from f77_ext_return_complex import t0,t8,t16,td,s0,s8,s16,sd + test_functions = [t0,t8,t16,td,s0,s8,s16,sd] + return test_functions + + +def runtest(t): + tname = t.__doc__.split()[0] + if tname in ['t0','t8','s0','s8']: + err = 1e-5 + else: + err = 0.0 + assert abs(t(234j)-234.0j)<=err + assert abs(t(234.6)-234.6)<=err + assert abs(t(234l)-234.0)<=err + assert abs(t(234.6+3j)-(234.6+3j))<=err + #assert abs(t('234')-234.)<=err + #assert abs(t('234.6')-234.6)<=err + assert abs(t(-234)+234.)<=err + assert abs(t([234])-234.)<=err + assert abs(t((234,))-234.)<=err + assert abs(t(array(234))-234.)<=err + assert abs(t(array(23+4j,'F'))-(23+4j))<=err + assert abs(t(array([234]))-234.)<=err + assert abs(t(array([[234]]))-234.)<=err + assert abs(t(array([234],'1'))+22.)<=err + assert abs(t(array([234],'s'))-234.)<=err + assert abs(t(array([234],'i'))-234.)<=err + assert abs(t(array([234],'l'))-234.)<=err + assert abs(t(array([234],'b'))-234.)<=err + assert abs(t(array([234],'f'))-234.)<=err + assert abs(t(array([234],'d'))-234.)<=err + assert abs(t(array([234+3j],'F'))-(234+3j))<=err + assert abs(t(array([234],'D'))-234.)<=err + + try: raise RuntimeError,`t(array([234],'c'))` + except TypeError: pass + try: raise RuntimeError,`t('abc')` + except TypeError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + try: + try: raise RuntimeError,`t(10l**400)` + except OverflowError: pass + except RuntimeError: + r = t(10l**400); assert `r` in ['(inf+0j)','(Infinity+0j)'],`r` + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/f77/return_integer.py b/numpy/f2py/tests/f77/return_integer.py new file mode 100644 index 000000000..f50ab52da --- /dev/null +++ b/numpy/f2py/tests/f77/return_integer.py @@ -0,0 +1,148 @@ + +__usage__ = """ +Run: + python return_integer.py [<f2py options>] +Examples: + python return_integer.py --fcompiler=Gnu --no-wrap-functions + python return_integer.py --quiet +""" + +import scipy.f2py as f2py2e +from scipy.base import array + +def build(f2py_opts): + try: + import f77_ext_return_integer + except ImportError: + assert not f2py2e.compile('''\ + function t0(value) + integer value + integer t0 + t0 = value + end + function t1(value) + integer*1 value + integer*1 t1 + t1 = value + end + function t2(value) + integer*2 value + integer*2 t2 + t2 = value + end + function t4(value) + integer*4 value + integer*4 t4 + t4 = value + end + function t8(value) + integer*8 value + integer*8 t8 + t8 = value + end + + subroutine s0(t0,value) + integer value + integer t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s1(t1,value) + integer*1 value + integer*1 t1 +cf2py intent(out) t1 + t1 = value + end + subroutine s2(t2,value) + integer*2 value + integer*2 t2 +cf2py intent(out) t2 + t2 = value + end + subroutine s4(t4,value) + integer*4 value + integer*4 t4 +cf2py intent(out) t4 + t4 = value + end + subroutine s8(t8,value) + integer*8 value + integer*8 t8 +cf2py intent(out) t8 + t8 = value + end + +''','f77_ext_return_integer',f2py_opts,source_fn='f77_ret_int.f') + + from f77_ext_return_integer import t0,t1,t2,t4,t8,s0,s1,s2,s4,s8 + test_functions = [t0,t1,t2,t4,t8,s0,s1,s2,s4,s8] + return test_functions + +def runtest(t): + import sys + assert t(123)==123,`t(123)` + assert t(123.6)==123 + assert t(123l)==123 + if sys.version[:3]<'2.3': + assert t(123.6+3j)==123 + assert t('123')==123 + assert t(-123)==-123 + assert t([123])==123 + assert t((123,))==123 + assert t(array(123))==123 + assert t(array([123]))==123 + assert t(array([[123]]))==123 + assert t(array([123],'b'))==123 + assert t(array([123],'h'))==123 + assert t(array([123],'i'))==123 + assert t(array([123],'l'))==123 + assert t(array([123],'B'))==123 + assert t(array([123],'f'))==123 + assert t(array([123],'d'))==123 + if sys.version[:3]<'2.3': + assert t(array([123+3j],'F'))==123 + assert t(array([123],'D'))==123 + + + try: raise RuntimeError,`t(array([123],'c'))` + except ValueError: pass + try: raise RuntimeError,`t('abc')` + except ValueError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + if t.__doc__.split()[0] in ['t8','s8']: + try: raise RuntimeError,`t(100000000000000000000000l)` + except OverflowError: pass + try: raise RuntimeError,`t(10000000011111111111111.23)` + except OverflowError: pass + else: + if sys.version[:3]<'2.3': + try: raise RuntimeError,`t(10000000000000l)` + except OverflowError: pass + try: raise RuntimeError,`t(10000000000.23)` + except OverflowError: pass + +if __name__=='__main__': + #import libwadpy + status = 1 + try: + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' + status = 0 + finally: + if status: + print '*'*20 + print 'Running f2py2e.diagnose' + import scipy.f2py.diagnose as diagnose + #diagnose.run() diff --git a/numpy/f2py/tests/f77/return_logical.py b/numpy/f2py/tests/f77/return_logical.py new file mode 100644 index 000000000..e252e03a6 --- /dev/null +++ b/numpy/f2py/tests/f77/return_logical.py @@ -0,0 +1,135 @@ + +__usage__ = """ +Run: + python return_logical.py [<f2py options>] +Examples: + python return_logical.py --fcompiler=Gnu --no-wrap-functions + python return_logical.py --quiet +""" + +import f2py2e +from Numeric import array +try: True +except NameError: + True = 1 + False = 0 + +def build(f2py_opts): + try: + import f77_ext_return_logical + except ImportError: + assert not f2py2e.compile('''\ + function t0(value) + logical value + logical t0 + t0 = value + end + function t1(value) + logical*1 value + logical*1 t1 + t1 = value + end + function t2(value) + logical*2 value + logical*2 t2 + t2 = value + end + function t4(value) + logical*4 value + logical*4 t4 + t4 = value + end +c function t8(value) +c logical*8 value +c logical*8 t8 +c t8 = value +c end + + subroutine s0(t0,value) + logical value + logical t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s1(t1,value) + logical*1 value + logical*1 t1 +cf2py intent(out) t1 + t1 = value + end + subroutine s2(t2,value) + logical*2 value + logical*2 t2 +cf2py intent(out) t2 + t2 = value + end + subroutine s4(t4,value) + logical*4 value + logical*4 t4 +cf2py intent(out) t4 + t4 = value + end +c subroutine s8(t8,value) +c logical*8 value +c logical*8 t8 +cf2py intent(out) t8 +c t8 = value +c end +''','f77_ext_return_logical',f2py_opts) + + #from f77_ext_return_logical import t0,t1,t2,t4,t8,s0,s1,s2,s4,s8 + #test_functions = [t0,t1,t2,t4,t8,s0,s1,s2,s4,s8] + from f77_ext_return_logical import t0,t1,t2,t4,s0,s1,s2,s4 + test_functions = [t0,t1,t2,t4,s0,s1,s2,s4] + return test_functions + +def runtest(t): + assert t(True)==1,`t(True)` + assert t(False)==0,`t(False)` + assert t(0)==0 + assert t(None)==0 + assert t(0.0)==0 + assert t(0j)==0 + assert t(1j)==1 + assert t(234)==1 + assert t(234.6)==1 + assert t(234l)==1 + assert t(234.6+3j)==1 + assert t('234')==1 + assert t('aaa')==1 + assert t('')==0 + assert t([])==0 + assert t(())==0 + assert t({})==0 + assert t(t)==1 + assert t(-234)==1 + assert t(10l**100)==1 + assert t([234])==1 + assert t((234,))==1 + assert t(array(234))==1 + assert t(array([234]))==1 + assert t(array([[234]]))==1 + assert t(array([234],'1'))==1 + assert t(array([234],'s'))==1 + assert t(array([234],'i'))==1 + assert t(array([234],'l'))==1 + assert t(array([234],'b'))==1 + assert t(array([234],'f'))==1 + assert t(array([234],'d'))==1 + assert t(array([234+3j],'F'))==1 + assert t(array([234],'D'))==1 + assert t(array(0))==0 + assert t(array([0]))==0 + assert t(array([[0]]))==0 + assert t(array([0j]))==0 + assert t(array([1]))==1 + assert t(array([0,0]))==0 + assert t(array([0,1]))==1 #XXX: is this expected? + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' + diff --git a/numpy/f2py/tests/f77/return_real.py b/numpy/f2py/tests/f77/return_real.py new file mode 100644 index 000000000..37f97a06d --- /dev/null +++ b/numpy/f2py/tests/f77/return_real.py @@ -0,0 +1,127 @@ +__usage__ = """ +Run: + python return_real.py [<f2py options>] +Examples: + python return_real.py --fcompiler=Gnu --no-wrap-functions + python return_real.py --quiet +""" + + +import scipy.f2py as f2py2e +from scipy.base import array + +def build(f2py_opts): + try: + import f77_ext_return_real + except ImportError: + assert not f2py2e.compile('''\ + function t0(value) + real value + real t0 + t0 = value + end + function t4(value) + real*4 value + real*4 t4 + t4 = value + end + function t8(value) + real*8 value + real*8 t8 + t8 = value + end + function td(value) + double precision value + double precision td + td = value + end + + subroutine s0(t0,value) + real value + real t0 +cf2py intent(out) t0 + t0 = value + end + subroutine s4(t4,value) + real*4 value + real*4 t4 +cf2py intent(out) t4 + t4 = value + end + subroutine s8(t8,value) + real*8 value + real*8 t8 +cf2py intent(out) t8 + t8 = value + end + subroutine sd(td,value) + double precision value + double precision td +cf2py intent(out) td + td = value + end +''','f77_ext_return_real',f2py_opts,source_fn='f77_ret_real.f') + + from f77_ext_return_real import t0,t4,t8,td,s0,s4,s8,sd + test_functions = [t0,t4,t8,td,s0,s4,s8,sd] + return test_functions + +def runtest(t): + import sys + if t.__doc__.split()[0] in ['t0','t4','s0','s4']: + err = 1e-5 + else: + err = 0.0 + assert abs(t(234)-234.0)<=err + assert abs(t(234.6)-234.6)<=err + assert abs(t(234l)-234.0)<=err + if sys.version[:3]<'2.3': + assert abs(t(234.6+3j)-234.6)<=err + assert abs(t('234')-234)<=err + assert abs(t('234.6')-234.6)<=err + assert abs(t(-234)+234)<=err + assert abs(t([234])-234)<=err + assert abs(t((234,))-234.)<=err + assert abs(t(array(234))-234.)<=err + assert abs(t(array([234]))-234.)<=err + assert abs(t(array([[234]]))-234.)<=err + assert abs(t(array([234],'b'))+22)<=err + assert abs(t(array([234],'h'))-234.)<=err + assert abs(t(array([234],'i'))-234.)<=err + assert abs(t(array([234],'l'))-234.)<=err + assert abs(t(array([234],'B'))-234.)<=err + assert abs(t(array([234],'f'))-234.)<=err + assert abs(t(array([234],'d'))-234.)<=err + if sys.version[:3]<'2.3': + assert abs(t(array([234+3j],'F'))-234.)<=err + assert abs(t(array([234],'D'))-234.)<=err + if t.__doc__.split()[0] in ['t0','t4','s0','s4']: + assert t(1e200)==t(1e300) # inf + + try: raise RuntimeError,`t(array([234],'c'))` + except ValueError: pass + try: raise RuntimeError,`t('abc')` + except ValueError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + try: + try: raise RuntimeError,`t(10l**400)` + except OverflowError: pass + except RuntimeError: + r = t(10l**400); assert `r` in ['inf','Infinity'],`r` + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/f90/return_character.py b/numpy/f2py/tests/f90/return_character.py new file mode 100644 index 000000000..0bd7be701 --- /dev/null +++ b/numpy/f2py/tests/f90/return_character.py @@ -0,0 +1,100 @@ + +__usage__ = """ +Run: + python return_character.py [<f2py options>] +Examples: + python return_character.py --fcompiler=Gnu --no-wrap-functions + python return_character.py --quiet +""" + +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import f90_ext_return_character + except ImportError: + assert not f2py2e.compile('''\ +module f90_return_char + contains + function t0(value) + character :: value + character :: t0 + t0 = value + end function t0 + function t1(value) + character(len=1) :: value + character(len=1) :: t1 + t1 = value + end function t1 + function t5(value) + character(len=5) :: value + character(len=5) :: t5 + t5 = value + end function t5 + function ts(value) + character(len=*) :: value + character(len=10) :: ts + ts = value + end function ts + + subroutine s0(t0,value) + character :: value + character :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s1(t1,value) + character(len=1) :: value + character(len=1) :: t1 +!f2py intent(out) t1 + t1 = value + end subroutine s1 + subroutine s5(t5,value) + character(len=5) :: value + character(len=5) :: t5 +!f2py intent(out) t5 + t5 = value + end subroutine s5 + subroutine ss(ts,value) + character(len=*) :: value + character(len=10) :: ts +!f2py intent(out) ts + ts = value + end subroutine ss +end module f90_return_char +''','f90_ext_return_character',f2py_opts,source_fn='f90_ret_char.f90') + + from f90_ext_return_character import f90_return_char as m + test_functions = [m.t0,m.t1,m.t5,m.ts,m.s0,m.s1,m.s5,m.ss] + return test_functions + + +def runtest(t): + tname = t.__doc__.split()[0] + if tname in ['t0','t1','s0','s1']: + assert t(23)=='2' + r = t('ab');assert r=='a',`r` + r = t(array('ab'));assert r=='a',`r` + r = t(array(77,'1'));assert r=='M',`r` + try: raise RuntimeError,`t(array([77,87]))` + except ValueError: pass + try: raise RuntimeError,`t(array(77))` + except ValueError: pass + elif tname in ['ts','ss']: + assert t(23)=='23 ',`t(23)` + assert t('123456789abcdef')=='123456789a',`t('123456789abcdef')` + elif tname in ['t5','s5']: + assert t(23)=='23 ' + assert t('ab')=='ab ' + assert t('123456789abcdef')=='12345' + else: + raise NotImplementedError + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' + diff --git a/numpy/f2py/tests/f90/return_complex.py b/numpy/f2py/tests/f90/return_complex.py new file mode 100644 index 000000000..36d8707fc --- /dev/null +++ b/numpy/f2py/tests/f90/return_complex.py @@ -0,0 +1,127 @@ +__usage__ = """ +Run: + python return_complex.py [<f2py options>] +Examples: + python return_complex.py --quiet +""" + + +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import f90_ext_return_complex + except ImportError: + assert not f2py2e.compile('''\ +module f90_return_complex + contains + function t0(value) + complex :: value + complex :: t0 + t0 = value + end function t0 + function t8(value) + complex(kind=4) :: value + complex(kind=4) :: t8 + t8 = value + end function t8 + function t16(value) + complex(kind=8) :: value + complex(kind=8) :: t16 + t16 = value + end function t16 + function td(value) + double complex :: value + double complex :: td + td = value + end function td + + subroutine s0(t0,value) + complex :: value + complex :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s8(t8,value) + complex(kind=4) :: value + complex(kind=4) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 + subroutine s16(t16,value) + complex(kind=8) :: value + complex(kind=8) :: t16 +!f2py intent(out) t16 + t16 = value + end subroutine s16 + subroutine sd(td,value) + double complex :: value + double complex :: td +!f2py intent(out) td + td = value + end subroutine sd +end module f90_return_complex +''','f90_ext_return_complex',f2py_opts,source_fn='f90_ret_cmlx.f90') + + from f90_ext_return_complex import f90_return_complex as m + test_functions = [m.t0,m.t8,m.t16,m.td,m.s0,m.s8,m.s16,m.sd] + return test_functions + + +def runtest(t): + tname = t.__doc__.split()[0] + if tname in ['t0','t8','s0','s8']: + err = 1e-5 + else: + err = 0.0 + #assert abs(t(234j)-234.0j)<=err + assert abs(t(234.6)-234.6)<=err + assert abs(t(234l)-234.0)<=err + assert abs(t(234.6+3j)-(234.6+3j))<=err + #assert abs(t('234')-234.)<=err + #assert abs(t('234.6')-234.6)<=err + assert abs(t(-234)+234.)<=err + assert abs(t([234])-234.)<=err + assert abs(t((234,))-234.)<=err + assert abs(t(array(234))-234.)<=err + assert abs(t(array(23+4j,'F'))-(23+4j))<=err + assert abs(t(array([234]))-234.)<=err + assert abs(t(array([[234]]))-234.)<=err + assert abs(t(array([234],'1'))+22.)<=err + assert abs(t(array([234],'s'))-234.)<=err + assert abs(t(array([234],'i'))-234.)<=err + assert abs(t(array([234],'l'))-234.)<=err + assert abs(t(array([234],'b'))-234.)<=err + assert abs(t(array([234],'f'))-234.)<=err + assert abs(t(array([234],'d'))-234.)<=err + assert abs(t(array([234+3j],'F'))-(234+3j))<=err + assert abs(t(array([234],'D'))-234.)<=err + + try: raise RuntimeError,`t(array([234],'c'))` + except TypeError: pass + try: raise RuntimeError,`t('abc')` + except TypeError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + try: + try: raise RuntimeError,`t(10l**400)` + except OverflowError: pass + except RuntimeError: + r = t(10l**400); assert `r` in ['(inf+0j)','(Infinity+0j)'],`r` + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/f90/return_integer.py b/numpy/f2py/tests/f90/return_integer.py new file mode 100644 index 000000000..635252ce9 --- /dev/null +++ b/numpy/f2py/tests/f90/return_integer.py @@ -0,0 +1,152 @@ + +# XXX: investigate cases that are disabled under win32 +# + +__usage__ = """ +Run: + python return_integer.py [<f2py options>] +Examples: + python return_integer.py --quiet +""" + +import sys +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import f90_ext_return_integer + except ImportError: + assert not f2py2e.compile('''\ +module f90_return_integer + contains + function t0(value) + integer :: value + integer :: t0 + t0 = value + end function t0 + function t1(value) + integer(kind=1) :: value + integer(kind=1) :: t1 + t1 = value + end function t1 + function t2(value) + integer(kind=2) :: value + integer(kind=2) :: t2 + t2 = value + end function t2 + function t4(value) + integer(kind=4) :: value + integer(kind=4) :: t4 + t4 = value + end function t4 + function t8(value) + integer(kind=8) :: value + integer(kind=8) :: t8 + t8 = value + end function t8 + + subroutine s0(t0,value) + integer :: value + integer :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s1(t1,value) + integer(kind=1) :: value + integer(kind=1) :: t1 +!f2py intent(out) t1 + t1 = value + end subroutine s1 + subroutine s2(t2,value) + integer(kind=2) :: value + integer(kind=2) :: t2 +!f2py intent(out) t2 + t2 = value + end subroutine s2 + subroutine s4(t4,value) + integer(kind=4) :: value + integer(kind=4) :: t4 +!f2py intent(out) t4 + t4 = value + end subroutine s4 + subroutine s8(t8,value) + integer(kind=8) :: value + integer(kind=8) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 +end module f90_return_integer +''','f90_ext_return_integer',f2py_opts,source_fn='f90_ret_int.f90') + + from f90_ext_return_integer import f90_return_integer as m + test_functions = [m.t0,m.t1,m.t2,m.t4,m.t8,m.s0,m.s1,m.s2,m.s4,m.s8] + return test_functions + +def runtest(t): + tname = t.__doc__.split()[0] + assert t(123)==123 + assert t(123.6)==123 + assert t(123l)==123 + if sys.version[:3]<='2.2': + assert t(123.6+3j)==123 + assert t('123')==123 + assert t(-123)==-123 + assert t([123])==123 + assert t((123,))==123 + assert t(array(123))==123 + assert t(array([123]))==123 + assert t(array([[123]]))==123 + assert t(array([123],'1'))==123 + assert t(array([123],'s'))==123 + assert t(array([123],'i'))==123 + assert t(array([123],'l'))==123 + assert t(array([123],'b'))==123 + assert t(array([123],'f'))==123 + assert t(array([123],'d'))==123 + if sys.version[:3]<='2.2': + assert t(array([123+3j],'F'))==123 + assert t(array([123],'D'))==123 + + try: raise RuntimeError,`t(array([123],'c'))` + except ValueError: pass + try: raise RuntimeError,`t('abc')` + except ValueError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + if tname in ['t8','s8']: + try: raise RuntimeError,`t(100000000000000000000000l)` + except OverflowError: pass + try: raise RuntimeError,`t(10000000011111111111111.23)` + except OverflowError: pass + else: + if sys.version[:3]<='2.2': + try: raise RuntimeError,`t(10000000000000l)` + except OverflowError: pass + try: raise RuntimeError,`t(10000000000.23)` + except OverflowError: pass + +if __name__=='__main__': + #import libwadpy + status = 1 + try: + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' + status = 0 + finally: + if status: + print '*'*20 + print 'Running f2py2e.diagnose' + import f2py2e.diagnose + f2py2e.diagnose.run() diff --git a/numpy/f2py/tests/f90/return_logical.py b/numpy/f2py/tests/f90/return_logical.py new file mode 100644 index 000000000..c9479edaf --- /dev/null +++ b/numpy/f2py/tests/f90/return_logical.py @@ -0,0 +1,138 @@ + +__usage__ = """ +Run: + python return_logical.py [<f2py options>] +Examples: + python return_logical.py --quiet +""" + +import f2py2e +from Numeric import array + +try: True +except NameError: + True = 1 + False = 0 + +def build(f2py_opts): + try: + import f90_ext_return_logical + except ImportError: + assert not f2py2e.compile('''\ +module f90_return_logical + contains + function t0(value) + logical :: value + logical :: t0 + t0 = value + end function t0 + function t1(value) + logical(kind=1) :: value + logical(kind=1) :: t1 + t1 = value + end function t1 + function t2(value) + logical(kind=2) :: value + logical(kind=2) :: t2 + t2 = value + end function t2 + function t4(value) + logical(kind=4) :: value + logical(kind=4) :: t4 + t4 = value + end function t4 + function t8(value) + logical(kind=8) :: value + logical(kind=8) :: t8 + t8 = value + end function t8 + + subroutine s0(t0,value) + logical :: value + logical :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s1(t1,value) + logical(kind=1) :: value + logical(kind=1) :: t1 +!f2py intent(out) t1 + t1 = value + end subroutine s1 + subroutine s2(t2,value) + logical(kind=2) :: value + logical(kind=2) :: t2 +!f2py intent(out) t2 + t2 = value + end subroutine s2 + subroutine s4(t4,value) + logical(kind=4) :: value + logical(kind=4) :: t4 +!f2py intent(out) t4 + t4 = value + end subroutine s4 + subroutine s8(t8,value) + logical(kind=8) :: value + logical(kind=8) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 +end module f90_return_logical +''','f90_ext_return_logical',f2py_opts,source_fn='f90_ret_log.f90') + + from f90_ext_return_logical import f90_return_logical as m + test_functions = [m.t0,m.t1,m.t2,m.t4,m.t8,m.s0,m.s1,m.s2,m.s4,m.s8] + return test_functions + + + + +def runtest(t): + assert t(True)==1,`t(True)` + assert t(False)==0,`t(False)` + assert t(0)==0 + assert t(None)==0 + assert t(0.0)==0 + assert t(0j)==0 + assert t(1j)==1 + assert t(234)==1 + assert t(234.6)==1 + assert t(234l)==1 + assert t(234.6+3j)==1 + assert t('234')==1 + assert t('aaa')==1 + assert t('')==0 + assert t([])==0 + assert t(())==0 + assert t({})==0 + assert t(t)==1 + assert t(-234)==1 + assert t(10l**100)==1 + assert t([234])==1 + assert t((234,))==1 + assert t(array(234))==1 + assert t(array([234]))==1 + assert t(array([[234]]))==1 + assert t(array([234],'1'))==1 + assert t(array([234],'s'))==1 + assert t(array([234],'i'))==1 + assert t(array([234],'l'))==1 + assert t(array([234],'b'))==1 + assert t(array([234],'f'))==1 + assert t(array([234],'d'))==1 + assert t(array([234+3j],'F'))==1 + assert t(array([234],'D'))==1 + assert t(array(0))==0 + assert t(array([0]))==0 + assert t(array([[0]]))==0 + assert t(array([0j]))==0 + assert t(array([1]))==1 + assert t(array([0,0]))==0 + assert t(array([0,1]))==1 #XXX: is this expected? + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/f90/return_real.py b/numpy/f2py/tests/f90/return_real.py new file mode 100644 index 000000000..263e28165 --- /dev/null +++ b/numpy/f2py/tests/f90/return_real.py @@ -0,0 +1,129 @@ +__usage__ = """ +Run: + python return_real.py [<f2py options>] +Examples: + python return_real.py --quiet +""" + +import sys +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import f90_ext_return_real + except ImportError: + assert not f2py2e.compile('''\ +module f90_return_real + contains + function t0(value) + real :: value + real :: t0 + t0 = value + end function t0 + function t4(value) + real(kind=4) :: value + real(kind=4) :: t4 + t4 = value + end function t4 + function t8(value) + real(kind=8) :: value + real(kind=8) :: t8 + t8 = value + end function t8 + function td(value) + double precision :: value + double precision :: td + td = value + end function td + + subroutine s0(t0,value) + real :: value + real :: t0 +!f2py intent(out) t0 + t0 = value + end subroutine s0 + subroutine s4(t4,value) + real(kind=4) :: value + real(kind=4) :: t4 +!f2py intent(out) t4 + t4 = value + end subroutine s4 + subroutine s8(t8,value) + real(kind=8) :: value + real(kind=8) :: t8 +!f2py intent(out) t8 + t8 = value + end subroutine s8 + subroutine sd(td,value) + double precision :: value + double precision :: td +!f2py intent(out) td + td = value + end subroutine sd +end module f90_return_real +''','f90_ext_return_real',f2py_opts,source_fn='f90_ret_real.f90') + + from f90_ext_return_real import f90_return_real as m + test_functions = [m.t0,m.t4,m.t8,m.td,m.s0,m.s4,m.s8,m.sd] + return test_functions + +def runtest(t): + tname = t.__doc__.split()[0] + if tname in ['t0','t4','s0','s4']: + err = 1e-5 + else: + err = 0.0 + assert abs(t(234)-234.0)<=err + assert abs(t(234.6)-234.6)<=err + assert abs(t(234l)-234.0)<=err + if sys.version[:3]<='2.2': + assert abs(t(234.6+3j)-234.6)<=err,`t(234.6+3j)` + assert abs(t('234')-234)<=err + assert abs(t('234.6')-234.6)<=err + assert abs(t(-234)+234)<=err + assert abs(t([234])-234)<=err + assert abs(t((234,))-234.)<=err + assert abs(t(array(234))-234.)<=err + assert abs(t(array([234]))-234.)<=err + assert abs(t(array([[234]]))-234.)<=err + assert abs(t(array([234],'1'))+22)<=err + assert abs(t(array([234],'s'))-234.)<=err + assert abs(t(array([234],'i'))-234.)<=err + assert abs(t(array([234],'l'))-234.)<=err + assert abs(t(array([234],'b'))-234.)<=err + assert abs(t(array([234],'f'))-234.)<=err + assert abs(t(array([234],'d'))-234.)<=err + if sys.version[:3]<='2.2': + assert abs(t(array([234+3j],'F'))-234.)<=err,`t(array([234+3j],'F'))` + assert abs(t(array([234],'D'))-234.)<=err,`t(array([234],'D'))` + if tname in ['t0','t4','s0','s4']: + assert t(1e200)==t(1e300) # inf + + try: raise RuntimeError,`t(array([234],'c'))` + except ValueError: pass + try: raise RuntimeError,`t('abc')` + except ValueError: pass + + try: raise RuntimeError,`t([])` + except IndexError: pass + try: raise RuntimeError,`t(())` + except IndexError: pass + + try: raise RuntimeError,`t(t)` + except TypeError: pass + try: raise RuntimeError,`t({})` + except TypeError: pass + + try: + try: raise RuntimeError,`t(10l**400)` + except OverflowError: pass + except RuntimeError: + r = t(10l**400); assert `r` in ['inf','Infinity'],`r` + +if __name__=='__main__': + #import libwadpy + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/mixed/foo.f b/numpy/f2py/tests/mixed/foo.f new file mode 100644 index 000000000..c34742578 --- /dev/null +++ b/numpy/f2py/tests/mixed/foo.f @@ -0,0 +1,5 @@ + subroutine bar11(a) +cf2py intent(out) a + integer a + a = 11 + end diff --git a/numpy/f2py/tests/mixed/foo_fixed.f90 b/numpy/f2py/tests/mixed/foo_fixed.f90 new file mode 100644 index 000000000..7543a6acb --- /dev/null +++ b/numpy/f2py/tests/mixed/foo_fixed.f90 @@ -0,0 +1,8 @@ + module foo_fixed + contains + subroutine bar12(a) +!f2py intent(out) a + integer a + a = 12 + end subroutine bar12 + end module foo_fixed diff --git a/numpy/f2py/tests/mixed/foo_free.f90 b/numpy/f2py/tests/mixed/foo_free.f90 new file mode 100644 index 000000000..c1b641f13 --- /dev/null +++ b/numpy/f2py/tests/mixed/foo_free.f90 @@ -0,0 +1,8 @@ +module foo_free +contains + subroutine bar13(a) + !f2py intent(out) a + integer a + a = 13 + end subroutine bar13 +end module foo_free diff --git a/numpy/f2py/tests/mixed/run.py b/numpy/f2py/tests/mixed/run.py new file mode 100644 index 000000000..6f4b7d444 --- /dev/null +++ b/numpy/f2py/tests/mixed/run.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +__usage__ = """ +Run: + python run.py [<f2py options>] +Examples: + python run.py --quiet +""" + +import os +import sys +import string +import f2py2e +from Numeric import array + +def build(f2py_opts): + try: + import mixed_f77_f90 + except: + d,b=os.path.split(sys.argv[0]) + files = ['foo.f','foo_fixed.f90','foo_free.f90'] + files = [os.path.join(d,f) for f in files] + files = string.join(files) + args = ' -c -m mixed_f77_f90 %s %s'%(files,f2py_opts) + c = '%s -c "import f2py2e;f2py2e.main()" %s' %(sys.executable,args) + s = os.system(c) + assert not s + from mixed_f77_f90 import bar11 + test_functions = [bar11] + from mixed_f77_f90 import foo_fixed as m + test_functions.append(m.bar12) + from mixed_f77_f90 import foo_free as m + test_functions.append(m.bar13) + return test_functions + +def runtest(t): + tname = t.__doc__.split()[0] + if tname=='bar11': + assert t()==11 + elif tname=='bar12': + assert t()==12 + elif tname=='bar13': + assert t()==13 + else: + raise NotImplementedError + +if __name__=='__main__': + repeat,f2py_opts = f2py2e.f2py_testing.cmdline() + test_functions = build(f2py_opts) + f2py2e.f2py_testing.run(runtest,test_functions,repeat) + print 'ok' diff --git a/numpy/f2py/tests/run_all.py b/numpy/f2py/tests/run_all.py new file mode 100755 index 000000000..016e68c29 --- /dev/null +++ b/numpy/f2py/tests/run_all.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +import os,sys + +opts = sys.argv[1:] +if not opts: + opts = ['10','--quiet'] + +NUMARRAY = "-DNUMARRAY" in sys.argv + +test_f77_files = [\ + 'f77/return_integer.py', + 'f77/return_logical.py', + 'f77/return_real.py', + 'f77/return_complex.py', + 'f77/callback.py', + ] + +if not NUMARRAY: # no support for character yet in numarray + test_f77_files.append('f77/return_character.py') + +test_f90_files = [\ + 'f90/return_integer.py', + 'f90/return_logical.py', + 'f90/return_real.py', + 'f90/return_complex.py', + 'f90/return_character.py', + 'mixed/run.py', + ] + +test_files = test_f77_files + +if NUMARRAY: + print >>sys.stderr,"NOTE: f2py for numarray does not support"\ + " f90 or character arrays." +else: + test_files += test_f90_files + +py_path = os.environ.get('PYTHONPATH') +if py_path is None: + py_path = '.' +else: + py_path = os.pathsep.join(['.',py_path]) +os.environ['PYTHONPATH'] = py_path + +for f in test_files: + print "**********************************************" + ff = os.path.join(sys.path[0],f) + args = [sys.executable,ff]+opts + print "Running",' '.join(args) + status = os.spawnve(os.P_WAIT,sys.executable,args,os.environ) + if status: + print 'TEST FAILURE (status=%s)' % (status) + if f=='f90/return_integer.py': + sys.exit() diff --git a/numpy/f2py/use_rules.py b/numpy/f2py/use_rules.py new file mode 100644 index 000000000..8affcbe41 --- /dev/null +++ b/numpy/f2py/use_rules.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +""" + +Build 'use others module data' mechanism for f2py2e. + +Unfinished. + +Copyright 2000 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@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. +$Date: 2000/09/10 12:35:43 $ +Pearu Peterson +""" + +__version__ = "$Revision: 1.3 $"[10:-1] + +f2py_version='See `f2py -v`' + +import pprint +import sys,string,time,types,copy +errmess=sys.stderr.write +outmess=sys.stdout.write +show=pprint.pprint + +from auxfuncs import * +import capi_maps +import cfuncs +############## + +usemodule_rules={ + 'body':""" +#begintitle# +static char doc_#apiname#[] = \"\\\nVariable wrapper signature:\\n\\ +\t #name# = get_#name#()\\n\\ +Arguments:\\n\\ +#docstr#\"; +extern F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#); +static PyObject *#apiname#(PyObject *capi_self, PyObject *capi_args) { +/*#decl#*/ +\tif (!PyArg_ParseTuple(capi_args, \"\")) goto capi_fail; +printf(\"c: %d\\n\",F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#)); +\treturn Py_BuildValue(\"\"); +capi_fail: +\treturn NULL; +} +""", + 'method':'\t{\"get_#name#\",#apiname#,METH_VARARGS|METH_KEYWORDS,doc_#apiname#},', + 'need':['F_MODFUNC'] + } + +################ + +def buildusevars(m,r): + ret={} + outmess('\t\tBuilding use variable hooks for module "%s" (feature only for F90/F95)...\n'%(m['name'])) + varsmap={} + revmap={} + if r.has_key('map'): + for k in r['map'].keys(): + if revmap.has_key(r['map'][k]): + outmess('\t\t\tVariable "%s<=%s" is already mapped by "%s". Skipping.\n'%(r['map'][k],k,revmap[r['map'][k]])) + else: + revmap[r['map'][k]]=k + if r.has_key('only') and r['only']: + for v in r['map'].keys(): + if m['vars'].has_key(r['map'][v]): + + if revmap[r['map'][v]]==v: + varsmap[v]=r['map'][v] + else: + outmess('\t\t\tIgnoring map "%s=>%s". See above.\n'%(v,r['map'][v])) + else: + outmess('\t\t\tNo definition for variable "%s=>%s". Skipping.\n'%(v,r['map'][v])) + else: + for v in m['vars'].keys(): + if revmap.has_key(v): + varsmap[v]=revmap[v] + else: + varsmap[v]=v + for v in varsmap.keys(): + ret=dictappend(ret,buildusevar(v,varsmap[v],m['vars'],m['name'])) + return ret +def buildusevar(name,realname,vars,usemodulename): + outmess('\t\t\tConstructing wrapper function for variable "%s=>%s"...\n'%(name,realname)) + ret={} + vrd={'name':name, + 'realname':realname, + 'REALNAME':string.upper(realname), + 'usemodulename':usemodulename, + 'USEMODULENAME':string.upper(usemodulename), + 'texname':string.replace(name,'_','\\_'), + 'begintitle':gentitle('%s=>%s'%(name,realname)), + 'endtitle':gentitle('end of %s=>%s'%(name,realname)), + 'apiname':'#modulename#_use_%s_from_%s'%(realname,usemodulename) + } + nummap={0:'Ro',1:'Ri',2:'Rii',3:'Riii',4:'Riv',5:'Rv',6:'Rvi',7:'Rvii',8:'Rviii',9:'Rix'} + vrd['texnamename']=name + for i in nummap.keys(): + vrd['texnamename']=string.replace(vrd['texnamename'],`i`,nummap[i]) + if hasnote(vars[realname]): vrd['note']=vars[realname]['note'] + rd=dictappend({},vrd) + var=vars[realname] + + print name,realname,vars[realname] + ret=applyrules(usemodule_rules,rd) + return ret + + + + + + |