aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/numpy/f2py/src
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/numpy/f2py/src
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/numpy/f2py/src')
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.c1423
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.h173
2 files changed, 1596 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.c b/.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.c
new file mode 100644
index 00000000..072392bb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.c
@@ -0,0 +1,1423 @@
+#define FORTRANOBJECT_C
+#include "fortranobject.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ 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 $
+*/
+
+int
+F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj)
+{
+ if (obj == NULL) {
+ fprintf(stderr, "Error loading %s\n", name);
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ return -1;
+ }
+ return PyDict_SetItemString(dict, name, obj);
+}
+
+/*
+ * Python-only fallback for thread-local callback pointers
+ */
+void *
+F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
+{
+ PyObject *local_dict, *value;
+ void *prev;
+
+ local_dict = PyThreadState_GetDict();
+ if (local_dict == NULL) {
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyThreadState_GetDict "
+ "failed");
+ }
+
+ value = PyDict_GetItemString(local_dict, key);
+ if (value != NULL) {
+ prev = PyLong_AsVoidPtr(value);
+ if (PyErr_Occurred()) {
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
+ }
+ }
+ else {
+ prev = NULL;
+ }
+
+ value = PyLong_FromVoidPtr((void *)ptr);
+ if (value == NULL) {
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyLong_FromVoidPtr failed");
+ }
+
+ if (PyDict_SetItemString(local_dict, key, value) != 0) {
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyDict_SetItemString failed");
+ }
+
+ Py_DECREF(value);
+
+ return prev;
+}
+
+void *
+F2PyGetThreadLocalCallbackPtr(char *key)
+{
+ PyObject *local_dict, *value;
+ void *prev;
+
+ local_dict = PyThreadState_GetDict();
+ if (local_dict == NULL) {
+ Py_FatalError(
+ "F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
+ }
+
+ value = PyDict_GetItemString(local_dict, key);
+ if (value != NULL) {
+ prev = PyLong_AsVoidPtr(value);
+ if (PyErr_Occurred()) {
+ Py_FatalError(
+ "F2PyGetThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
+ }
+ }
+ else {
+ prev = NULL;
+ }
+
+ return prev;
+}
+
+static PyArray_Descr *
+get_descr_from_type_and_elsize(const int type_num, const int elsize) {
+ PyArray_Descr * descr = PyArray_DescrFromType(type_num);
+ if (type_num == NPY_STRING) {
+ // PyArray_DescrFromType returns descr with elsize = 0.
+ PyArray_DESCR_REPLACE(descr);
+ if (descr == NULL) {
+ return NULL;
+ }
+ descr->elsize = elsize;
+ }
+ return descr;
+}
+
+/************************* 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))();
+ }
+ fp = PyObject_New(PyFortranObject, &PyFortran_Type);
+ if (fp == NULL) {
+ return NULL;
+ }
+ if ((fp->dict = PyDict_New()) == NULL) {
+ Py_DECREF(fp);
+ 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) {
+ goto fail;
+ }
+ PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
+ Py_XDECREF(v);
+ }
+ else if ((fp->defs[i].data) !=
+ NULL) { /* Is Fortran variable or array (not allocatable) */
+ PyArray_Descr *
+ descr = get_descr_from_type_and_elsize(fp->defs[i].type,
+ fp->defs[i].elsize);
+ if (descr == NULL) {
+ goto fail;
+ }
+ v = PyArray_NewFromDescr(&PyArray_Type, descr, fp->defs[i].rank,
+ fp->defs[i].dims.d, NULL, fp->defs[i].data,
+ NPY_ARRAY_FARRAY, NULL);
+ if (v == NULL) {
+ Py_DECREF(descr);
+ goto fail;
+ }
+ PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
+ Py_XDECREF(v);
+ }
+ }
+ return (PyObject *)fp;
+fail:
+ Py_XDECREF(fp);
+ 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) {
+ PyObject_Del(fp);
+ return NULL;
+ }
+ fp->len = 1;
+ fp->defs = defs;
+ if (defs->rank == -1) {
+ PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("function %s", defs->name));
+ } else if (defs->rank == 0) {
+ PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("scalar %s", defs->name));
+ } else {
+ PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("array %s", defs->name));
+ }
+ return (PyObject *)fp;
+}
+
+/* Fortran methods */
+
+static void
+fortran_dealloc(PyFortranObject *fp)
+{
+ Py_XDECREF(fp->dict);
+ PyObject_Del(fp);
+}
+
+/* Returns number of bytes consumed from buf, or -1 on error. */
+static Py_ssize_t
+format_def(char *buf, Py_ssize_t size, FortranDataDef def)
+{
+ char *p = buf;
+ int i;
+ npy_intp n;
+
+ n = PyOS_snprintf(p, size, "array(%" NPY_INTP_FMT, def.dims.d[0]);
+ if (n < 0 || n >= size) {
+ return -1;
+ }
+ p += n;
+ size -= n;
+
+ for (i = 1; i < def.rank; i++) {
+ n = PyOS_snprintf(p, size, ",%" NPY_INTP_FMT, def.dims.d[i]);
+ if (n < 0 || n >= size) {
+ return -1;
+ }
+ p += n;
+ size -= n;
+ }
+
+ if (size <= 0) {
+ return -1;
+ }
+
+ *p++ = ')';
+ size--;
+
+ if (def.data == NULL) {
+ static const char notalloc[] = ", not allocated";
+ if ((size_t)size < sizeof(notalloc)) {
+ return -1;
+ }
+ memcpy(p, notalloc, sizeof(notalloc));
+ p += sizeof(notalloc);
+ size -= sizeof(notalloc);
+ }
+
+ return p - buf;
+}
+
+static PyObject *
+fortran_doc(FortranDataDef def)
+{
+ char *buf, *p;
+ PyObject *s = NULL;
+ Py_ssize_t n, origsize, size = 100;
+
+ if (def.doc != NULL) {
+ size += strlen(def.doc);
+ }
+ origsize = size;
+ buf = p = (char *)PyMem_Malloc(size);
+ if (buf == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ if (def.rank == -1) {
+ if (def.doc) {
+ n = strlen(def.doc);
+ if (n > size) {
+ goto fail;
+ }
+ memcpy(p, def.doc, n);
+ p += n;
+ size -= n;
+ }
+ else {
+ n = PyOS_snprintf(p, size, "%s - no docs available", def.name);
+ if (n < 0 || n >= size) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+ }
+ }
+ else {
+ PyArray_Descr *d = PyArray_DescrFromType(def.type);
+ n = PyOS_snprintf(p, size, "%s : '%c'-", def.name, d->type);
+ Py_DECREF(d);
+ if (n < 0 || n >= size) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+
+ if (def.data == NULL) {
+ n = format_def(p, size, def);
+ if (n < 0) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+ }
+ else if (def.rank > 0) {
+ n = format_def(p, size, def);
+ if (n < 0) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+ }
+ else {
+ n = strlen("scalar");
+ if (size < n) {
+ goto fail;
+ }
+ memcpy(p, "scalar", n);
+ p += n;
+ size -= n;
+ }
+ }
+ if (size <= 1) {
+ goto fail;
+ }
+ *p++ = '\n';
+ size--;
+
+ /* p now points one beyond the last character of the string in buf */
+ s = PyUnicode_FromStringAndSize(buf, p - buf);
+
+ PyMem_Free(buf);
+ return s;
+
+fail:
+ fprintf(stderr,
+ "fortranobject.c: fortran_doc: len(p)=%zd>%zd=size:"
+ " too long docstring required, increase size\n",
+ p - buf, origsize);
+ PyMem_Free(buf);
+ return NULL;
+}
+
+static FortranDataDef *save_def; /* save pointer of an allocatable array */
+static void
+set_data(char *d, npy_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_GetItemStringWithError(fp->dict, name);
+ if (v == NULL && PyErr_Occurred()) {
+ return NULL;
+ }
+ else 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, NPY_ARRAY_FARRAY, NULL);
+ if (v == NULL)
+ return NULL;
+ /* Py_INCREF(v); */
+ return v;
+ }
+ else { /* array is not allocated */
+ Py_RETURN_NONE;
+ }
+ }
+ if (strcmp(name, "__dict__") == 0) {
+ Py_INCREF(fp->dict);
+ return fp->dict;
+ }
+ if (strcmp(name, "__doc__") == 0) {
+ PyObject *s = PyUnicode_FromString(""), *s2, *s3;
+ for (i = 0; i < fp->len; i++) {
+ s2 = fortran_doc(fp->defs[i]);
+ s3 = PyUnicode_Concat(s, s2);
+ Py_DECREF(s2);
+ Py_DECREF(s);
+ s = s3;
+ }
+ if (PyDict_SetItemString(fp->dict, name, s))
+ return NULL;
+ return s;
+ }
+ if ((strcmp(name, "_cpointer") == 0) && (fp->len == 1)) {
+ PyObject *cobj =
+ F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data), NULL);
+ if (PyDict_SetItemString(fp->dict, name, cobj))
+ return NULL;
+ return cobj;
+ }
+ PyObject *str, *ret;
+ str = PyUnicode_FromString(name);
+ ret = PyObject_GenericGetAttr((PyObject *)fp, str);
+ Py_DECREF(str);
+ return ret;
+}
+
+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 */
+ npy_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, PyArray_DIMS(arr),
+ 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(npy_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 */
+ npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,
+ PyArray_NDIM(arr));
+ if (s == -1)
+ s = PyArray_MultiplyList(PyArray_DIMS(arr), PyArray_NDIM(arr));
+ if (s < 0 || (memcpy(fp->defs[i].data, PyArray_DATA(arr),
+ 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; /* successful */
+ }
+ 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;
+}
+
+static PyObject *
+fortran_repr(PyFortranObject *fp)
+{
+ PyObject *name = NULL, *repr = NULL;
+ name = PyObject_GetAttrString((PyObject *)fp, "__name__");
+ PyErr_Clear();
+ if (name != NULL && PyUnicode_Check(name)) {
+ repr = PyUnicode_FromFormat("<fortran %U>", name);
+ }
+ else {
+ repr = PyUnicode_FromString("<fortran object>");
+ }
+ Py_XDECREF(name);
+ return repr;
+}
+
+PyTypeObject PyFortran_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0).tp_name = "fortran",
+ .tp_basicsize = sizeof(PyFortranObject),
+ .tp_dealloc = (destructor)fortran_dealloc,
+ .tp_getattr = (getattrfunc)fortran_getattr,
+ .tp_setattr = (setattrfunc)fortran_setattr,
+ .tp_repr = (reprfunc)fortran_repr,
+ .tp_call = (ternaryfunc)fortran_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 (actual) : %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 npy_intp arr_size = PyArray_Size((PyObject *)arr);
+ if (arr_size > F2PY_REPORT_ON_ARRAY_COPY) {
+ fprintf(stderr,
+ "copied an array: size=%ld, elsize=%" NPY_INTP_FMT "\n",
+ arr_size, (npy_intp)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 contiguous 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 check_and_fix_dimensions(const PyArrayObject* arr,
+ const int rank,
+ npy_intp *dims,
+ const char *errmess);
+
+static int
+find_first_negative_dimension(const int rank, const npy_intp *dims)
+{
+ int i;
+ for (i = 0; i < rank; ++i) {
+ if (dims[i] < 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+#ifdef DEBUG_COPY_ND_ARRAY
+void
+dump_dims(int rank, npy_intp const *dims)
+{
+ int i;
+ printf("[");
+ for (i = 0; i < rank; ++i) {
+ printf("%3" NPY_INTP_FMT, dims[i]);
+ }
+ printf("]\n");
+}
+void
+dump_attrs(const PyArrayObject *obj)
+{
+ const PyArrayObject_fields *arr = (const PyArrayObject_fields *)obj;
+ int rank = PyArray_NDIM(arr);
+ npy_intp size = PyArray_Size((PyObject *)arr);
+ printf("\trank = %d, flags = %d, size = %" NPY_INTP_FMT "\n", rank,
+ arr->flags, size);
+ printf("\tstrides = ");
+ dump_dims(rank, arr->strides);
+ printf("\tdimensions = ");
+ dump_dims(rank, arr->dimensions);
+}
+#endif
+
+#define SWAPTYPE(a, b, t) \
+ { \
+ t c; \
+ c = (a); \
+ (a) = (b); \
+ (b) = c; \
+ }
+
+static int
+swap_arrays(PyArrayObject *obj1, PyArrayObject *obj2)
+{
+ PyArrayObject_fields *arr1 = (PyArrayObject_fields *)obj1,
+ *arr2 = (PyArrayObject_fields *)obj2;
+ SWAPTYPE(arr1->data, arr2->data, char *);
+ SWAPTYPE(arr1->nd, arr2->nd, int);
+ SWAPTYPE(arr1->dimensions, arr2->dimensions, npy_intp *);
+ SWAPTYPE(arr1->strides, arr2->strides, npy_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)) || \
+ (PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)) || \
+ (PyArray_ISSTRING(arr) && PyTypeNum_ISSTRING(type_num)))
+
+static int
+get_elsize(PyObject *obj) {
+ /*
+ get_elsize determines array itemsize from a Python object. Returns
+ elsize if successful, -1 otherwise.
+
+ Supported types of the input are: numpy.ndarray, bytes, str, tuple,
+ list.
+ */
+
+ if (PyArray_Check(obj)) {
+ return PyArray_DESCR((PyArrayObject *)obj)->elsize;
+ } else if (PyBytes_Check(obj)) {
+ return PyBytes_GET_SIZE(obj);
+ } else if (PyUnicode_Check(obj)) {
+ return PyUnicode_GET_LENGTH(obj);
+ } else if (PySequence_Check(obj)) {
+ PyObject* fast = PySequence_Fast(obj, "f2py:fortranobject.c:get_elsize");
+ if (fast != NULL) {
+ Py_ssize_t i, n = PySequence_Fast_GET_SIZE(fast);
+ int sz, elsize = 0;
+ for (i=0; i<n; i++) {
+ sz = get_elsize(PySequence_Fast_GET_ITEM(fast, i) /* borrowed */);
+ if (sz > elsize) {
+ elsize = sz;
+ }
+ }
+ Py_DECREF(fast);
+ return elsize;
+ }
+ }
+ return -1;
+}
+
+extern PyArrayObject *
+ndarray_from_pyobj(const int type_num,
+ const int elsize_,
+ npy_intp *dims,
+ const int rank,
+ const int intent,
+ PyObject *obj,
+ const char *errmess) {
+ /*
+ * Return an array with given element type and shape from a Python
+ * object while taking into account the usage intent of the array.
+ *
+ * - element type is defined by type_num and elsize
+ * - shape is defined by dims and rank
+ *
+ * ndarray_from_pyobj is used to convert Python object arguments
+ * to numpy ndarrays with given type and shape that data is passed
+ * to interfaced Fortran or C functions.
+ *
+ * errmess (if not NULL), contains a prefix of an error message
+ * for an exception to be triggered within this function.
+ *
+ * Negative elsize value means that elsize is to be determined
+ * from the Python object in runtime.
+ *
+ * Note on strings
+ * ---------------
+ *
+ * String type (type_num == NPY_STRING) does not have fixed
+ * element size and, by default, the type object sets it to
+ * 0. Therefore, for string types, one has to use elsize
+ * argument. For other types, elsize value is ignored.
+ *
+ * NumPy defines the type of a fixed-width string as
+ * dtype('S<width>'). In addition, there is also dtype('c'), that
+ * appears as dtype('S1') (these have the same type_num value),
+ * but is actually different (.char attribute is either 'S' or
+ * 'c', respecitely).
+ *
+ * In Fortran, character arrays and strings are different
+ * concepts. The relation between Fortran types, NumPy dtypes,
+ * and type_num-elsize pairs, is defined as follows:
+ *
+ * character*5 foo | dtype('S5') | elsize=5, shape=()
+ * character(5) foo | dtype('S1') | elsize=1, shape=(5)
+ * character*5 foo(n) | dtype('S5') | elsize=5, shape=(n,)
+ * character(5) foo(n) | dtype('S1') | elsize=1, shape=(5, n)
+ * character*(*) foo | dtype('S') | elsize=-1, shape=()
+ *
+ * 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[F2PY_MESSAGE_BUFFER_SIZE];
+ PyArrayObject *arr = NULL;
+ int elsize = (elsize_ < 0 ? get_elsize(obj) : elsize_);
+ if (elsize < 0) {
+ if (errmess != NULL) {
+ strcpy(mess, errmess);
+ }
+ sprintf(mess + strlen(mess),
+ " -- failed to determine element size from %s",
+ Py_TYPE(obj)->tp_name);
+ PyErr_SetString(PyExc_SystemError, mess);
+ return NULL;
+ }
+ PyArray_Descr * descr = get_descr_from_type_and_elsize(type_num, elsize); // new reference
+ if (descr == NULL) {
+ return NULL;
+ }
+ elsize = descr->elsize;
+ if ((intent & F2PY_INTENT_HIDE)
+ || ((intent & F2PY_INTENT_CACHE) && (obj == Py_None))
+ || ((intent & F2PY_OPTIONAL) && (obj == Py_None))
+ ) {
+ /* intent(cache), optional, intent(hide) */
+ int ineg = find_first_negative_dimension(rank, dims);
+ if (ineg >= 0) {
+ int i;
+ strcpy(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), "%" NPY_INTP_FMT ",", dims[i]);
+ strcat(mess, ")");
+ PyErr_SetString(PyExc_ValueError, mess);
+ Py_DECREF(descr);
+ return NULL;
+ }
+ arr = (PyArrayObject *) \
+ PyArray_NewFromDescr(&PyArray_Type, descr, rank, dims,
+ NULL, NULL, !(intent & F2PY_INTENT_C), NULL);
+ if (arr == NULL) {
+ Py_DECREF(descr);
+ return NULL;
+ }
+ if (PyArray_ITEMSIZE(arr) != elsize) {
+ strcpy(mess, "failed to create intent(cache|hide)|optional array");
+ sprintf(mess+strlen(mess)," -- expected elsize=%d got %" NPY_INTP_FMT, elsize, (npy_intp)PyArray_ITEMSIZE(arr));
+ PyErr_SetString(PyExc_ValueError,mess);
+ Py_DECREF(arr);
+ return 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(arr)
+ && PyArray_ITEMSIZE(arr) >= elsize) {
+ if (check_and_fix_dimensions(arr, rank, dims, errmess)) {
+ Py_DECREF(descr);
+ return NULL;
+ }
+ if (intent & F2PY_INTENT_OUT)
+ Py_INCREF(arr);
+ Py_DECREF(descr);
+ return arr;
+ }
+ strcpy(mess, "failed to initialize intent(cache) array");
+ if (!PyArray_ISONESEGMENT(arr))
+ strcat(mess, " -- input must be in one segment");
+ if (PyArray_ITEMSIZE(arr) < elsize)
+ sprintf(mess + strlen(mess),
+ " -- expected at least elsize=%d but got "
+ "%" NPY_INTP_FMT,
+ elsize, (npy_intp)PyArray_ITEMSIZE(arr));
+ PyErr_SetString(PyExc_ValueError, mess);
+ Py_DECREF(descr);
+ return NULL;
+ }
+
+ /* here we have always intent(in) or intent(inout) or intent(inplace)
+ */
+
+ if (check_and_fix_dimensions(arr, rank, dims, errmess)) {
+ Py_DECREF(descr);
+ return NULL;
+ }
+ /*
+ printf("intent alignment=%d\n", F2PY_GET_ALIGNMENT(intent));
+ printf("alignment check=%d\n", F2PY_CHECK_ALIGNMENT(arr, intent));
+ int i;
+ for (i=1;i<=16;i++)
+ printf("i=%d isaligned=%d\n", i, ARRAY_ISALIGNED(arr, i));
+ */
+ if ((! (intent & F2PY_INTENT_COPY)) &&
+ PyArray_ITEMSIZE(arr) == elsize &&
+ ARRAY_ISCOMPATIBLE(arr,type_num) &&
+ F2PY_CHECK_ALIGNMENT(arr, intent)) {
+ if ((intent & F2PY_INTENT_INOUT || intent & F2PY_INTENT_INPLACE)
+ ? ((intent & F2PY_INTENT_C) ? PyArray_ISCARRAY(arr) : PyArray_ISFARRAY(arr))
+ : ((intent & F2PY_INTENT_C) ? PyArray_ISCARRAY_RO(arr) : PyArray_ISFARRAY_RO(arr))) {
+ if ((intent & F2PY_INTENT_OUT)) {
+ Py_INCREF(arr);
+ }
+ /* Returning input array */
+ Py_DECREF(descr);
+ return arr;
+ }
+ }
+ if (intent & F2PY_INTENT_INOUT) {
+ strcpy(mess, "failed to initialize intent(inout) array");
+ /* Must use PyArray_IS*ARRAY because intent(inout) requires
+ * writable input */
+ if ((intent & F2PY_INTENT_C) && !PyArray_ISCARRAY(arr))
+ strcat(mess, " -- input not contiguous");
+ if (!(intent & F2PY_INTENT_C) && !PyArray_ISFARRAY(arr))
+ strcat(mess, " -- input not fortran contiguous");
+ if (PyArray_ITEMSIZE(arr) != elsize)
+ sprintf(mess + strlen(mess),
+ " -- expected elsize=%d but got %" NPY_INTP_FMT,
+ elsize,
+ (npy_intp)PyArray_ITEMSIZE(arr)
+ );
+ if (!(ARRAY_ISCOMPATIBLE(arr, type_num))) {
+ sprintf(mess + strlen(mess),
+ " -- input '%c' not compatible to '%c'",
+ PyArray_DESCR(arr)->type, descr->type);
+ }
+ if (!(F2PY_CHECK_ALIGNMENT(arr, intent)))
+ sprintf(mess + strlen(mess), " -- input not %d-aligned",
+ F2PY_GET_ALIGNMENT(intent));
+ PyErr_SetString(PyExc_ValueError, mess);
+ Py_DECREF(descr);
+ return NULL;
+ }
+
+ /* here we have always intent(in) or intent(inplace) */
+
+ {
+ PyArrayObject * retarr = (PyArrayObject *) \
+ PyArray_NewFromDescr(&PyArray_Type, descr, PyArray_NDIM(arr), PyArray_DIMS(arr),
+ NULL, NULL, !(intent & F2PY_INTENT_C), NULL);
+ if (retarr==NULL) {
+ Py_DECREF(descr);
+ 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)) {
+ Py_DECREF(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)) {
+ PyErr_Format(PyExc_TypeError,
+ "failed to initialize intent(inout|inplace|cache) "
+ "array, input '%s' object is not an array",
+ Py_TYPE(obj)->tp_name);
+ Py_DECREF(descr);
+ return NULL;
+ }
+
+ {
+ F2PY_REPORT_ON_ARRAY_COPY_FROMANY;
+ arr = (PyArrayObject *)PyArray_FromAny(
+ obj, descr, 0, 0,
+ ((intent & F2PY_INTENT_C) ? NPY_ARRAY_CARRAY
+ : NPY_ARRAY_FARRAY) |
+ NPY_ARRAY_FORCECAST,
+ NULL);
+ // Warning: in the case of NPY_STRING, PyArray_FromAny may
+ // reset descr->elsize, e.g. dtype('S0') becomes dtype('S1').
+ if (arr == NULL) {
+ Py_DECREF(descr);
+ return NULL;
+ }
+ if (type_num != NPY_STRING && PyArray_ITEMSIZE(arr) != elsize) {
+ // This is internal sanity tests: elsize has been set to
+ // descr->elsize in the beginning of this function.
+ strcpy(mess, "failed to initialize intent(in) array");
+ sprintf(mess + strlen(mess),
+ " -- expected elsize=%d got %" NPY_INTP_FMT, elsize,
+ (npy_intp)PyArray_ITEMSIZE(arr));
+ PyErr_SetString(PyExc_ValueError, mess);
+ Py_DECREF(arr);
+ return NULL;
+ }
+ if (check_and_fix_dimensions(arr, rank, dims, errmess)) {
+ Py_DECREF(arr);
+ return NULL;
+ }
+ return arr;
+ }
+}
+
+extern PyArrayObject *
+array_from_pyobj(const int type_num,
+ npy_intp *dims,
+ const int rank,
+ const int intent,
+ PyObject *obj) {
+ /*
+ Same as ndarray_from_pyobj but with elsize determined from type,
+ if possible. Provided for backward compatibility.
+ */
+ PyArray_Descr* descr = PyArray_DescrFromType(type_num);
+ int elsize = descr->elsize;
+ Py_DECREF(descr);
+ return ndarray_from_pyobj(type_num, elsize, dims, rank, intent, obj, NULL);
+}
+
+/*****************************************/
+/* Helper functions for array_from_pyobj */
+/*****************************************/
+
+static int
+check_and_fix_dimensions(const PyArrayObject* arr, const int rank,
+ npy_intp *dims, const char *errmess)
+{
+ /*
+ * 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.
+ *
+ * Returns 0 if the function is successful.
+ *
+ * If an error condition is detected, an exception is set and 1 is
+ * returned.
+ */
+ char mess[F2PY_MESSAGE_BUFFER_SIZE];
+ const npy_intp arr_size =
+ (PyArray_NDIM(arr)) ? PyArray_Size((PyObject *)arr) : 1;
+#ifdef DEBUG_COPY_ND_ARRAY
+ dump_attrs(arr);
+ printf("check_and_fix_dimensions:init: dims=");
+ dump_dims(rank, dims);
+#endif
+ if (rank > PyArray_NDIM(arr)) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */
+ npy_intp new_size = 1;
+ int free_axe = -1;
+ int i;
+ npy_intp d;
+ /* Fill dims where -1 or 0; check dimensions; calc new_size; */
+ for (i = 0; i < PyArray_NDIM(arr); ++i) {
+ d = PyArray_DIM(arr, i);
+ if (dims[i] >= 0) {
+ if (d > 1 && dims[i] != d) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%d-th dimension must be fixed to %" NPY_INTP_FMT
+ " but got %" NPY_INTP_FMT "\n",
+ i, dims[i], d);
+ return 1;
+ }
+ if (!dims[i])
+ dims[i] = 1;
+ }
+ else {
+ dims[i] = d ? d : 1;
+ }
+ new_size *= dims[i];
+ }
+ for (i = PyArray_NDIM(arr); i < rank; ++i)
+ if (dims[i] > 1) {
+ PyErr_Format(PyExc_ValueError,
+ "%d-th dimension must be %" NPY_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) {
+ PyErr_Format(PyExc_ValueError,
+ "unexpected array size: new_size=%" NPY_INTP_FMT
+ ", got array with arr_size=%" NPY_INTP_FMT
+ " (maybe too many free indices)\n",
+ new_size, arr_size);
+ return 1;
+ }
+ }
+ else if (rank == PyArray_NDIM(arr)) {
+ npy_intp new_size = 1;
+ int i;
+ npy_intp d;
+ for (i = 0; i < rank; ++i) {
+ d = PyArray_DIM(arr, i);
+ if (dims[i] >= 0) {
+ if (d > 1 && d != dims[i]) {
+ if (errmess != NULL) {
+ strcpy(mess, errmess);
+ }
+ sprintf(mess + strlen(mess),
+ " -- %d-th dimension must be fixed to %"
+ NPY_INTP_FMT " but got %" NPY_INTP_FMT,
+ i, dims[i], d);
+ PyErr_SetString(PyExc_ValueError, mess);
+ return 1;
+ }
+ if (!dims[i])
+ dims[i] = 1;
+ }
+ else
+ dims[i] = d;
+ new_size *= dims[i];
+ }
+ if (new_size != arr_size) {
+ PyErr_Format(PyExc_ValueError,
+ "unexpected array size: new_size=%" NPY_INTP_FMT
+ ", got array with arr_size=%" NPY_INTP_FMT "\n",
+ new_size, arr_size);
+ return 1;
+ }
+ }
+ else { /* [[1,2]] -> [[1],[2]] */
+ int i, j;
+ npy_intp d;
+ int effrank;
+ npy_intp size;
+ for (i = 0, effrank = 0; i < PyArray_NDIM(arr); ++i)
+ if (PyArray_DIM(arr, i) > 1)
+ ++effrank;
+ if (dims[rank - 1] >= 0)
+ if (effrank > rank) {
+ PyErr_Format(PyExc_ValueError,
+ "too many axes: %d (effrank=%d), "
+ "expected rank=%d\n",
+ PyArray_NDIM(arr), effrank, rank);
+ return 1;
+ }
+
+ for (i = 0, j = 0; i < rank; ++i) {
+ while (j < PyArray_NDIM(arr) && PyArray_DIM(arr, j) < 2) ++j;
+ if (j >= PyArray_NDIM(arr))
+ d = 1;
+ else
+ d = PyArray_DIM(arr, j++);
+ if (dims[i] >= 0) {
+ if (d > 1 && d != dims[i]) {
+ if (errmess != NULL) {
+ strcpy(mess, errmess);
+ }
+ sprintf(mess + strlen(mess),
+ " -- %d-th dimension must be fixed to %"
+ NPY_INTP_FMT " but got %" NPY_INTP_FMT
+ " (real index=%d)\n",
+ i, dims[i], d, j-1);
+ PyErr_SetString(PyExc_ValueError, mess);
+ return 1;
+ }
+ if (!dims[i])
+ dims[i] = 1;
+ }
+ else
+ dims[i] = d;
+ }
+
+ for (i = rank; i < PyArray_NDIM(arr);
+ ++i) { /* [[1,2],[3,4]] -> [1,2,3,4] */
+ while (j < PyArray_NDIM(arr) && PyArray_DIM(arr, j) < 2) ++j;
+ if (j >= PyArray_NDIM(arr))
+ d = 1;
+ else
+ d = PyArray_DIM(arr, j++);
+ dims[rank - 1] *= d;
+ }
+ for (i = 0, size = 1; i < rank; ++i) size *= dims[i];
+ if (size != arr_size) {
+ char msg[200];
+ int len;
+ snprintf(msg, sizeof(msg),
+ "unexpected array size: size=%" NPY_INTP_FMT
+ ", arr_size=%" NPY_INTP_FMT
+ ", rank=%d, effrank=%d, arr.nd=%d, dims=[",
+ size, arr_size, rank, effrank, PyArray_NDIM(arr));
+ for (i = 0; i < rank; ++i) {
+ len = strlen(msg);
+ snprintf(msg + len, sizeof(msg) - len, " %" NPY_INTP_FMT,
+ dims[i]);
+ }
+ len = strlen(msg);
+ snprintf(msg + len, sizeof(msg) - len, " ], arr.dims=[");
+ for (i = 0; i < PyArray_NDIM(arr); ++i) {
+ len = strlen(msg);
+ snprintf(msg + len, sizeof(msg) - len, " %" NPY_INTP_FMT,
+ PyArray_DIM(arr, i));
+ }
+ len = strlen(msg);
+ snprintf(msg + len, sizeof(msg) - len, " ]\n");
+ PyErr_SetString(PyExc_ValueError, msg);
+ return 1;
+ }
+ }
+#ifdef DEBUG_COPY_ND_ARRAY
+ printf("check_and_fix_dimensions:end: dims=");
+ dump_dims(rank, dims);
+#endif
+ 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);
+}
+
+/********************* Various utility functions ***********************/
+
+extern int
+f2py_describe(PyObject *obj, char *buf) {
+ /*
+ Write the description of a Python object to buf. The caller must
+ provide buffer with size sufficient to write the description.
+
+ Return 1 on success.
+ */
+ char localbuf[F2PY_MESSAGE_BUFFER_SIZE];
+ if (PyBytes_Check(obj)) {
+ sprintf(localbuf, "%d-%s", (npy_int)PyBytes_GET_SIZE(obj), Py_TYPE(obj)->tp_name);
+ } else if (PyUnicode_Check(obj)) {
+ sprintf(localbuf, "%d-%s", (npy_int)PyUnicode_GET_LENGTH(obj), Py_TYPE(obj)->tp_name);
+ } else if (PyArray_CheckScalar(obj)) {
+ PyArrayObject* arr = (PyArrayObject*)obj;
+ sprintf(localbuf, "%c%" NPY_INTP_FMT "-%s-scalar", PyArray_DESCR(arr)->kind, PyArray_ITEMSIZE(arr), Py_TYPE(obj)->tp_name);
+ } else if (PyArray_Check(obj)) {
+ int i;
+ PyArrayObject* arr = (PyArrayObject*)obj;
+ strcpy(localbuf, "(");
+ for (i=0; i<PyArray_NDIM(arr); i++) {
+ if (i) {
+ strcat(localbuf, " ");
+ }
+ sprintf(localbuf + strlen(localbuf), "%" NPY_INTP_FMT ",", PyArray_DIM(arr, i));
+ }
+ sprintf(localbuf + strlen(localbuf), ")-%c%" NPY_INTP_FMT "-%s", PyArray_DESCR(arr)->kind, PyArray_ITEMSIZE(arr), Py_TYPE(obj)->tp_name);
+ } else if (PySequence_Check(obj)) {
+ sprintf(localbuf, "%d-%s", (npy_int)PySequence_Length(obj), Py_TYPE(obj)->tp_name);
+ } else {
+ sprintf(localbuf, "%s instance", Py_TYPE(obj)->tp_name);
+ }
+ // TODO: detect the size of buf and make sure that size(buf) >= size(localbuf).
+ strcpy(buf, localbuf);
+ return 1;
+}
+
+extern npy_intp
+f2py_size_impl(PyArrayObject* var, ...)
+{
+ npy_intp sz = 0;
+ npy_intp dim;
+ npy_intp rank;
+ va_list argp;
+ va_start(argp, var);
+ dim = va_arg(argp, npy_int);
+ if (dim==-1)
+ {
+ sz = PyArray_SIZE(var);
+ }
+ else
+ {
+ rank = PyArray_NDIM(var);
+ if (dim>=1 && dim<=rank)
+ sz = PyArray_DIM(var, dim-1);
+ else
+ fprintf(stderr, "f2py_size: 2nd argument value=%" NPY_INTP_FMT
+ " fails to satisfy 1<=value<=%" NPY_INTP_FMT
+ ". Result will be 0.\n", dim, rank);
+ }
+ va_end(argp);
+ return sz;
+}
+
+/*********************************************/
+/* Compatibility functions for Python >= 3.0 */
+/*********************************************/
+
+PyObject *
+F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *))
+{
+ PyObject *ret = PyCapsule_New(ptr, NULL, dtor);
+ if (ret == NULL) {
+ PyErr_Clear();
+ }
+ return ret;
+}
+
+void *
+F2PyCapsule_AsVoidPtr(PyObject *obj)
+{
+ void *ret = PyCapsule_GetPointer(obj, NULL);
+ if (ret == NULL) {
+ PyErr_Clear();
+ }
+ return ret;
+}
+
+int
+F2PyCapsule_Check(PyObject *ptr)
+{
+ return PyCapsule_CheckExact(ptr);
+}
+
+#ifdef __cplusplus
+}
+#endif
+/************************* EOF fortranobject.c *******************************/
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.h b/.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.h
new file mode 100644
index 00000000..abd699c2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/src/fortranobject.h
@@ -0,0 +1,173 @@
+#ifndef Py_FORTRANOBJECT_H
+#define Py_FORTRANOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+
+#ifndef NPY_NO_DEPRECATED_API
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#endif
+#ifdef FORTRANOBJECT_C
+#define NO_IMPORT_ARRAY
+#endif
+#define PY_ARRAY_UNIQUE_SYMBOL _npy_f2py_ARRAY_API
+#include "numpy/arrayobject.h"
+#include "numpy/npy_3kcompat.h"
+
+#ifdef F2PY_REPORT_ATEXIT
+#include <sys/timeb.h>
+// clang-format off
+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 *);
+// clang-format on
+#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
+#define F2PY_MESSAGE_BUFFER_SIZE 300 // Increase on "stack smashing detected"
+
+typedef void (*f2py_set_data_func)(char *, npy_intp *);
+typedef void (*f2py_void_func)(void);
+typedef void (*f2py_init_func)(int *, npy_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 {
+ npy_intp d[F2PY_MAX_DIMS];
+ } dims; /* dimensions of the array, || not used */
+ int type; /* PyArray_<type> || not used */
+ int elsize; /* Element size || 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) (Py_TYPE(op) == &PyFortran_Type)
+#define PyFortran_Check1(op) (0 == strcmp(Py_TYPE(op)->tp_name, "fortran"))
+
+extern PyTypeObject PyFortran_Type;
+extern int
+F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj);
+extern PyObject *
+PyFortranObject_New(FortranDataDef *defs, f2py_void_func init);
+extern PyObject *
+PyFortranObject_NewAsAttr(FortranDataDef *defs);
+
+PyObject *
+F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *));
+void *
+F2PyCapsule_AsVoidPtr(PyObject *obj);
+int
+F2PyCapsule_Check(PyObject *ptr);
+
+extern void *
+F2PySwapThreadLocalCallbackPtr(char *key, void *ptr);
+extern void *
+F2PyGetThreadLocalCallbackPtr(char *key);
+
+#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_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
+#define F2PY_INTENT_ALIGNED4 512
+#define F2PY_INTENT_ALIGNED8 1024
+#define F2PY_INTENT_ALIGNED16 2048
+
+#define ARRAY_ISALIGNED(ARR, SIZE) ((size_t)(PyArray_DATA(ARR)) % (SIZE) == 0)
+#define F2PY_ALIGN4(intent) (intent & F2PY_INTENT_ALIGNED4)
+#define F2PY_ALIGN8(intent) (intent & F2PY_INTENT_ALIGNED8)
+#define F2PY_ALIGN16(intent) (intent & F2PY_INTENT_ALIGNED16)
+
+#define F2PY_GET_ALIGNMENT(intent) \
+ (F2PY_ALIGN4(intent) \
+ ? 4 \
+ : (F2PY_ALIGN8(intent) ? 8 : (F2PY_ALIGN16(intent) ? 16 : 1)))
+#define F2PY_CHECK_ALIGNMENT(arr, intent) \
+ ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent))
+#define F2PY_ARRAY_IS_CHARACTER_COMPATIBLE(arr) ((PyArray_DESCR(arr)->type_num == NPY_STRING && PyArray_DESCR(arr)->elsize >= 1) \
+ || PyArray_DESCR(arr)->type_num == NPY_UINT8)
+#define F2PY_IS_UNICODE_ARRAY(arr) (PyArray_DESCR(arr)->type_num == NPY_UNICODE)
+
+extern PyArrayObject *
+ndarray_from_pyobj(const int type_num, const int elsize_, npy_intp *dims,
+ const int rank, const int intent, PyObject *obj,
+ const char *errmess);
+
+extern PyArrayObject *
+array_from_pyobj(const int type_num, npy_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
+
+ extern int f2py_describe(PyObject *obj, char *buf);
+
+ /* Utility CPP macros and functions that can be used in signature file
+ expressions. See signature-file.rst for documentation.
+ */
+
+#define f2py_itemsize(var) (PyArray_DESCR((capi_ ## var ## _as_array))->elsize)
+#define f2py_size(var, ...) f2py_size_impl((PyArrayObject *)(capi_ ## var ## _as_array), ## __VA_ARGS__, -1)
+#define f2py_rank(var) var ## _Rank
+#define f2py_shape(var,dim) var ## _Dims[dim]
+#define f2py_len(var) f2py_shape(var,0)
+#define f2py_fshape(var,dim) f2py_shape(var,rank(var)-dim-1)
+#define f2py_flen(var) f2py_fshape(var,0)
+#define f2py_slen(var) capi_ ## var ## _len
+
+ extern npy_intp f2py_size_impl(PyArrayObject* var, ...);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_FORTRANOBJECT_H */