2
This module provides an interface to the UMFPACK library. The
3
license of the UMFPACK library is available below.
5
UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A.
6
Davis. All Rights Reserved.
10
Your use or distribution of UMFPACK or any modified version of
11
UMFPACK implies that you agree to this License.
13
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
14
EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
16
Permission is hereby granted to use or copy this program, provided
17
that the Copyright, this License, and the Availability of the original
18
version is retained on all copies. User documentation of any code that
19
uses UMFPACK or any modified version of UMFPACK code must cite the
20
Copyright, this License, the Availability note, and "Used by permission."
21
Permission to modify the code and to distribute modified code is granted,
22
provided the Copyright, this License, and the Availability note are
23
retained, and a notice that the code was modified is included. This
24
software was developed with support from the National Science Foundation,
25
and is provided to you free of charge.
29
http://www.cise.ufl.edu/research/sparse/umfpack
31
--------------------------------------------------------------------------------
33
AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A.
34
Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
38
Your use or distribution of AMD or any modified version of
39
AMD implies that you agree to this License.
41
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
42
EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
44
Permission is hereby granted to use or copy this program, provided
45
that the Copyright, this License, and the Availability of the original
46
version is retained on all copies. User documentation of any code that
47
uses AMD or any modified version of AMD code must cite the
48
Copyright, this License, the Availability note, and "Used by permission."
49
Permission to modify the code and to distribute modified code is granted,
50
provided the Copyright, this License, and the Availability note are
51
retained, and a notice that the code was modified is included. This
52
software was developed with support from the National Science Foundation,
53
and is provided to you free of charge.
57
http://www.cise.ufl.edu/research/sparse/amd
62
#define PY_ARRAY_UNIQUE_SYMBOL umfpack
63
#include "numpy/arrayobject.h"
65
#include "pysparse/spmatrix.h"
67
/***********************************************************************
68
* UMFPackObject definition
71
typedef struct UMFPackObject {
75
double *val; /* pointer to array of values */
76
int *row; /* pointer to array of indices */
77
int *ind; /* pointer to array of indices */
83
/***********************************************************************
84
* UMFPackObject methods
87
static char getlists_doc[] = "";
90
UMFPack_getlists(UMFPackObject *self, PyObject *args) {
91
PyObject *ind=NULL, *row=NULL, *val=NULL, *tupleret=NULL;
94
if (!PyArg_ParseTuple(args, ""))
97
ind = PyList_New(self->n+1);
101
PyList_SetItem(ind, 0, Py_BuildValue("i", 0));
102
for (i=1; i < (self->n + 1); i++) {
103
PyList_SetItem(ind, i, Py_BuildValue("i", self->ind[i] ));
106
row = PyList_New(self->nnz);
110
for (i=0; i < self->nnz; i++) {
111
PyList_SetItem(row, i, Py_BuildValue("i", self->row[i]));
114
val = PyList_New(self->nnz);
118
for (i=0; i < self->nnz; i++) {
119
PyList_SetItem(val, i, Py_BuildValue("d", self->val[i]));
122
tupleret = PyTuple_New(3);
123
if (tupleret == NULL)
126
PyTuple_SetItem(tupleret, 0, ind);
127
PyTuple_SetItem(tupleret, 1, row);
128
PyTuple_SetItem(tupleret, 2, val);
139
if (tupleret != NULL)
140
PyObject_Del(tupleret);
141
return PyErr_NoMemory();
144
static char solve_doc[] = "self.solve(b, x, systype)\n\
146
solves linear system of equations.\n\
151
b array, right hand side of equation\n\
152
x array, solution vector\n\
153
systype 'UMFPACK_A': solve A * x == b\n\
154
'UMFPACK_At': solve A^T * x == b\n\
155
'UMFPACK_Pt_L': solve P^T * L * x == b\n\
156
'UMFPACK_L': solve L * x == b\n\
157
'UMFPACK_Lt_P': solve L^T * P * x == b\n\
158
'UMFPACK_Lt': solve L^T * x == b\n\
159
'UMFPACK_U_Qt': solve U * Q^T * x == b\n\
160
'UMFPACK_U': solve U * x == b\n\
161
'UMFPACK_Q_Ut': solve Q * U^T * x == b\n\
162
'UMFPACK_Ut': solve U^T * x == b\n\
166
UMFPack_solve(UMFPackObject *self, PyObject *args) {
167
PyArrayObject *b, *x;
168
char *systype = "UMFPACK_A";
171
if (!PyArg_ParseTuple(args, "O!O!|s",
177
SPMATRIX_CHECK_ARR_DIM_SIZE(b, 1, self->n);
178
SPMATRIX_CHECK_ARR_DIM_SIZE(x, 1, self->n);
180
if (strcmp(systype, "UMFPACK_A") == 0)
182
else if (strcmp(systype, "UMFPACK_At") == 0)
184
else if (strcmp(systype, "UMFPACK_Pt_L") == 0)
186
else if (strcmp(systype, "UMFPACK_L") == 0)
188
else if (strcmp(systype, "UMFPACK_Lt_P") == 0)
190
else if (strcmp(systype, "UMFPACK_Lt") == 0)
192
else if (strcmp(systype, "UMFPACK_U_Qt") == 0)
194
else if (strcmp(systype, "UMFPACK_U") == 0)
196
else if (strcmp(systype, "UMFPACK_Q_Ut") == 0)
198
else if (strcmp(systype, "UMFPACK_Ut") == 0)
201
PyErr_SetString(PyExc_ValueError, "systype");
205
status = umfpack_di_solve(sys, self->ind, self->row, self->val,
206
(double *)x->data, (double *)b->data, self->Numeric,
207
self->Control, self->Info);
210
case UMFPACK_WARNING_singular_matrix:
211
PyErr_SetString(PyExc_SystemError, "singular matrix");
213
case UMFPACK_ERROR_out_of_memory:
214
PyErr_SetString(PyExc_SystemError, "insufficient memory");
216
case UMFPACK_ERROR_argument_missing:
217
PyErr_SetString(PyExc_SystemError, "one or more argument missing");
219
case UMFPACK_ERROR_invalid_system:
220
PyErr_SetString(PyExc_SystemError, "matrix is not square");
222
case UMFPACK_ERROR_invalid_Numeric_object:
223
PyErr_SetString(PyExc_SystemError, "invalid Numeric object");
231
/** table of object methods
233
PyMethodDef UMFPack_methods[] = {
234
{"solve", (PyCFunction)UMFPack_solve, METH_VARARGS, solve_doc},
235
{"getlists", (PyCFunction)UMFPack_getlists, METH_VARARGS, getlists_doc},
236
{NULL, NULL} /* sentinel */
240
/***********************************************************************
241
* UMFPackType methods
245
UMFPack_dealloc(UMFPackObject *self)
247
umfpack_di_free_numeric(&(self->Numeric));
248
PyMem_Free(self->val);
249
PyMem_Free(self->row);
250
PyMem_Free(self->ind);
251
PyMem_Free(self->Control);
252
PyMem_Free(self->Info);
257
UMFPack_getattr(UMFPackObject *self, char *name)
259
if (strcmp(name, "shape") == 0)
260
return Py_BuildValue("(i,i)", self->n, self->n);
261
if (strcmp(name, "nnz") == 0)
262
return Py_BuildValue("i", self->nnz);
263
if (strcmp(name, "__members__") == 0) {
264
char *members[] = {"shape", "nnz"};
267
PyObject *list = PyList_New(sizeof(members)/sizeof(char *));
269
for (i = 0; i < sizeof(members)/sizeof(char *); i ++)
270
PyList_SetItem(list, i, PyString_FromString(members[i]));
271
if (PyErr_Occurred()) {
278
return Py_FindMethod(UMFPack_methods, (PyObject *)self, name);
282
/***********************************************************************
283
* UMFPackType structure
286
PyTypeObject UMFPackType = {
287
PyObject_HEAD_INIT(NULL)
290
sizeof(UMFPackObject),
292
(destructor)UMFPack_dealloc, /* tp_dealloc */
294
(getattrfunc)UMFPack_getattr, /* tp_getattr */
299
0, /* tp_as_sequence*/
300
0, /* tp_as_mapping*/
304
/***********************************************************************
305
* Object construction functions
308
/***********************************************************************
312
static void sortcol(int *row, double *val, int n)
317
for (i=n-1; i > 0; i--) {
319
for (j=0; j < i; j++) {
320
if (row[j] > row[j+1]) {
322
/* swap row indices */
340
newUMFPackObject(LLMatObject *matrix, int strategy, double tol2by2, int scale,
341
double tolpivot, double tolsympivot, int irstep)
345
struct llColIndex *colidx;
346
int i, validx, curridx, status;
348
if (SpMatrix_LLMatBuildColIndex(&colidx, matrix, 1) == 1)
351
self = PyObject_New(UMFPackObject, &UMFPackType);
353
return PyErr_NoMemory();
355
/* initialize pointers to arrays */
359
self->Control = NULL;
361
self->Numeric = NULL;
363
self->n = matrix->dim[0];
365
self->nnz = 2 * colidx->nzLo + colidx->nzDiag + 2 * colidx->nzUp;
367
self->nnz = matrix->nnz;
369
self->val = (double *)PyMem_Malloc(self->nnz * sizeof(double));
370
if (self->val == NULL)
373
self->row = (int *)PyMem_Malloc(self->nnz * sizeof(int));
374
if (self->row == NULL) {
377
self->ind = (int *)PyMem_Malloc((self->n + 1) * sizeof(int) );
378
if (self->ind == NULL) {
381
self->ind[self->n] = self->nnz;
383
self->Control = (double *)PyMem_Malloc(UMFPACK_CONTROL * sizeof(double));
384
if (self->Control == NULL) {
388
umfpack_di_defaults(self->Control);
391
self->Control[UMFPACK_STRATEGY] = strategy;
394
self->Control[UMFPACK_2BY2_TOLERANCE] = tol2by2;
397
self->Control[UMFPACK_SCALE] = scale;
400
self->Control[UMFPACK_PIVOT_TOLERANCE] = tolpivot;
402
if (tolsympivot != -1)
403
self->Control[UMFPACK_SYM_PIVOT_TOLERANCE] = tolsympivot;
406
self->Control[UMFPACK_IRSTEP] = irstep;
408
self->Info = (double *)PyMem_Malloc(UMFPACK_INFO * sizeof(double));
409
if (self->Info == NULL) {
414
for (i=0; i < self->n; i++) {
415
self->ind[i] = validx;
416
for (curridx=colidx->root[i]; curridx != -1; curridx = colidx->link[curridx]) {
417
self->val[validx] = matrix->val[curridx];
418
self->row[validx++] = colidx->row[curridx];
422
for (curridx=matrix->root[i]; curridx != -1; curridx = matrix->link[curridx]) {
423
if (i != matrix->col[curridx]) {
424
self->val[validx] = matrix->val[curridx];
425
self->row[validx++] = matrix->col[curridx];
430
sortcol(&(self->row[self->ind[i]]), &(self->val[self->ind[i]]), validx - self->ind[i]);
433
status = umfpack_di_symbolic(self->n, self->n, self->ind, self->row, self->val, &Symbolic, self->Control, self->Info);
436
case UMFPACK_ERROR_n_nonpositive:
437
PyErr_SetString(PyExc_SystemError, "n must be positive");
439
case UMFPACK_ERROR_out_of_memory:
440
PyErr_SetString(PyExc_SystemError, "insufficient memory");
442
case UMFPACK_ERROR_argument_missing:
443
PyErr_SetString(PyExc_SystemError, "one or more argument missing");
445
case UMFPACK_ERROR_invalid_matrix:
446
PyErr_SetString(PyExc_SystemError, "invalid matrix");
448
case UMFPACK_ERROR_internal_error:
449
PyErr_SetString(PyExc_SystemError, "bug in umfpack");
453
status = umfpack_di_numeric(self->ind, self->row, self->val, Symbolic, &(self->Numeric), self->Control, self->Info);
457
case UMFPACK_WARNING_singular_matrix:
458
PyErr_SetString(PyExc_SystemError, "singular matrix");
460
case UMFPACK_ERROR_out_of_memory:
461
PyErr_SetString(PyExc_SystemError, "insufficient memory");
463
case UMFPACK_ERROR_argument_missing:
464
PyErr_SetString(PyExc_SystemError, "one or more argument missing");
466
case UMFPACK_ERROR_invalid_Symbolic_object:
467
PyErr_SetString(PyExc_SystemError, "invalid symbolic object");
469
case UMFPACK_ERROR_different_pattern:
470
PyErr_SetString(PyExc_SystemError, "matrix has changed since last factorization");
474
umfpack_di_free_symbolic(&Symbolic);
479
SpMatrix_LLMatDestroyColIndex(&colidx);
480
if (self->val != NULL)
481
PyMem_Free(self->val);
482
if (self->row != NULL)
483
PyMem_Free(self->row);
484
if (self->ind != NULL)
485
PyMem_Free(self->ind);
486
if (self->Control != NULL)
487
PyMem_Free(self->Control);
488
if (self->Info != NULL)
489
PyMem_Free(self->Info);
491
return PyErr_NoMemory();
495
static char factorize_doc[] = "factorize(A, ...)\n\
497
performs a factorization of the sparse matrix A (which is a ll_mat object) and \n\
498
return a umfpack_context object.\n\
503
A spmatrix.ll_mat object.\n\
504
Matrix to be factorized\n\
506
additional keyword arguments:\n\
507
-----------------------------\n\
509
strategy determines what kind of ordering and\n\
510
pivoting strategy that UMFPACK should use.\n\
511
\"UMFPACK_STRATEGY_AUTO\"\n\
512
\"UMFPACK_STRATEGY_UNSYMMETRIC\"\n\
513
\"UMFPACK_STRATEGY_SYMMETRIC\"\n\
514
\"UMFPACK_STRATEGY_2BY2\"\n\
516
tol2by2 tolerance for the 2 by 2 strategy\n\
518
scale scaling UMFPACK would use\n\
519
\"UMFPACK_SCALE_NONE\"\n\
520
\"UMFPACK_SCALE_SUM\"\n\
521
\"UMFPACK_SCALE_MAX\"\n\
523
tolpivot relative pivot tolerance for threshold partial\n\
524
pivoting with row interchanges.\n\
526
tolsympivot if diagonal pivoting is attempted then this\n\
527
parameter is used to control when the diagonal\n\
528
is selected in a given pivot column.\n\
530
irstep number of iterative refinement steps to attempt.\
534
factorize(PyObject *self, PyObject *args, PyObject *keywds) {
536
char *strategy="UMFPACK_STRATEGY_AUTO";
537
double tol2by2 = 0.1;
538
char *scale="UMFPACK_SCALE_SUM";
539
double tolpivot = 0.1;
540
double tolsympivot = 0.0;
543
int strategyval, scaleval;
545
static char *kwlist[] = {"", "strategy", "tol2by2", "scale", "tolpivot", "tolsympivot", "irstep", NULL};
547
res = PyArg_ParseTupleAndKeywords(args, keywds, "O!|sdsddi", kwlist,
558
if (strcmp("UMFPACK_STRATEGY_AUTO", strategy) == 0)
559
strategyval = UMFPACK_STRATEGY_AUTO;
560
else if (strcmp("UMFPACK_STRATEGY_UNSYMMETRIC", strategy) == 0)
561
strategyval = UMFPACK_STRATEGY_UNSYMMETRIC;
562
else if (strcmp("UMFPACK_STRATEGY_SYMMETRIC", strategy) == 0)
563
strategyval = UMFPACK_STRATEGY_SYMMETRIC;
564
else if (strcmp("UMFPACK_STRATEGY_2BY2", strategy) == 0)
565
strategyval = UMFPACK_STRATEGY_2BY2;
567
if (strcmp("UMFPACK_SCALE_NONE", scale) == 0)
568
scaleval = UMFPACK_SCALE_NONE;
569
else if (strcmp("UMFPACK_SCALE_SUM", scale) == 0)
570
scaleval = UMFPACK_SCALE_SUM;
571
if (strcmp("UMFPACK_SCALE_MAX", scale) == 0)
572
scaleval = UMFPACK_SCALE_MAX;
574
return newUMFPackObject(matrix, strategyval, tol2by2, scaleval, tolpivot, tolsympivot, irstep);
578
/** table of module functions
580
static PyMethodDef precon_methods[] = {
581
{"factorize", (PyCFunction)factorize, METH_VARARGS|METH_KEYWORDS, factorize_doc},
582
{NULL, NULL} /* sentinel */
591
UMFPackType.ob_type = &PyType_Type;
593
m = Py_InitModule("umfpack", precon_methods);
594
d = PyModule_GetDict(m);
596
PyDict_SetItemString(d, "UMFPackType", (PyObject *)&UMFPackType);
598
/* initialize Numeric array module */
600
/* initialize spmatrix module */
603
/* No need to check the error here, the caller will do that */