static cholmod_sparse *pack(spmatrix *A, char uplo) { int j, k, n = SP_NROWS(A), nnz = 0, cnt = 0; cholmod_sparse *B; if (uplo == 'L'){ for (j=0; j<n; j++){ for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] < j; k++); nnz += SP_COL(A)[j+1] - k; } if (!(B = CHOL(allocate_sparse)(n, n, nnz, 1, 1, -1, (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), &Common))) return 0; for (j=0; j<n; j++){ for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] < j; k++); for (; k<SP_COL(A)[j+1]; k++) { if (SP_ID(A) == DOUBLE) ((double *)B->x)[cnt] = SP_VALD(A)[k]; else ((double complex *)B->x)[cnt] = SP_VALZ(A)[k]; ((int_t *)B->p)[j+1]++; ((int_t *)B->i)[cnt++] = SP_ROW(A)[k]; } } } else { for (j=0; j<n; j++) for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] <= j; k++) nnz++; if (!(B = CHOL(allocate_sparse)(n, n, nnz, 1, 1, 1, (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), &Common))) return 0; for (j=0; j<n; j++) for (k=SP_COL(A)[j]; k<SP_COL(A)[j+1] && SP_ROW(A)[k] <= j; k++) { if (SP_ID(A) == DOUBLE) ((double *)B->x)[cnt] = SP_VALD(A)[k]; else ((double complex *)B->x)[cnt] = SP_VALZ(A)[k]; ((int_t *)B->p)[j+1]++; ((int_t *)B->i)[cnt++] = SP_ROW(A)[k]; } } for (j=0; j<n; j++) ((int_t *)B->p)[j+1] += ((int_t *)B->p)[j]; return B; }
static PyObject* getfactor(PyObject *self, PyObject *args) { PyObject *F; cholmod_factor *Lf; cholmod_sparse *Ls; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif if (!set_options()) return NULL; if (!PyArg_ParseTuple(args, "O", &F)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); Lf = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); Lf = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif /* Check factorization */ if (Lf->xtype == CHOLMOD_PATTERN) PY_ERR(PyExc_ValueError, "F must be a numeric Cholesky factor"); if (!(Ls = CHOL(factor_to_sparse)(Lf, &Common))) return PyErr_NoMemory(); spmatrix *ret = SpMatrix_New(Ls->nrow, Ls->ncol, Ls->nzmax, (Ls->xtype == CHOLMOD_REAL ? DOUBLE : COMPLEX)); if (!ret) { CHOL(free_sparse)(&Ls, &Common); return PyErr_NoMemory(); } memcpy(SP_COL(ret), Ls->p, (Ls->ncol+1)*sizeof(int_t)); memcpy(SP_ROW(ret), Ls->i, (Ls->nzmax)*sizeof(int_t)); memcpy(SP_VAL(ret), Ls->x, (Ls->nzmax)*E_SIZE[SP_ID(ret)]); CHOL(free_sparse)(&Ls, &Common); return (PyObject *)ret; }
PyMODINIT_FUNC initcholmod(void) { CHOL(start) (&Common); cholmod_module = Py_InitModule3("cvxopt.cholmod", cholmod_functions, cholmod__doc__); PyModule_AddObject(cholmod_module, "options", PyDict_New()); if (import_cvxopt() < 0) return; }
PyMODINIT_FUNC PyInit_cholmod(void) { CHOL(start) (&Common); if (!(cholmod_module = PyModule_Create(&cholmod_module_def))) return NULL; PyModule_AddObject(cholmod_module, "options", PyDict_New()); if (import_cvxopt() < 0) return NULL; return cholmod_module; }
static cholmod_sparse * create_matrix(spmatrix *A) { cholmod_sparse *B; if (!(B = CHOL(allocate_sparse)(SP_NROWS(A), SP_NCOLS(A), 0, 1, 0, 0, (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), &Common))) return NULL; int i; for (i=0; i<SP_NCOLS(A); i++) ((int_t *)B->nz)[i] = SP_COL(A)[i+1] - SP_COL(A)[i]; B->x = SP_VAL(A); B->i = SP_ROW(A); B->nzmax = SP_NNZ(A); memcpy(B->p, SP_COL(A), (SP_NCOLS(A)+1)*sizeof(int_t)); return B; }
static PyObject* splinsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A, *B, *X; matrix *P=NULL; int n, nnz; cholmod_sparse *Ac=NULL, *Bc=NULL, *Xc=NULL; cholmod_factor *L=NULL; #if PY_MAJOR_VERSION >= 3 int uplo_='L'; #endif char uplo='L'; char *kwlist[] = {"A", "B", "p", "uplo", NULL}; if (!set_options()) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OC", kwlist, &A, &B, &P, &uplo_)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oc", kwlist, &A, &B, &P, &uplo)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a square sparse matrix"); n = SP_NROWS(A); nnz = SP_NNZ(A); if (!SpMatrix_Check(B) || SP_ID(A) != SP_ID(B)) PY_ERR_TYPE("B must be a sparse matrix of the same type as A"); if (SP_NROWS(B) != n) PY_ERR(PyExc_ValueError, "incompatible dimensions for B"); if (P) { if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p"); if (MAT_LGT(P) != n) err_buf_len("p"); if (!CHOL(check_perm)(P->buffer, n, n, &Common)) PY_ERR(PyExc_ValueError, "not a valid permutation"); } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); L = CHOL(analyze_p) (Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common); if (Common.status != CHOLMOD_OK){ CHOL(free_factor)(&L, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else { PyErr_SetString(PyExc_ValueError, "symbolic factorization " "failed"); return NULL; } } CHOL(factorize) (Ac, L, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status > 0) switch (Common.status) { case CHOLMOD_NOT_POSDEF: PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", L->minor)); CHOL(free_factor)(&L, &Common); return NULL; break; case CHOLMOD_DSMALL: /* This never happens unless we change the default value * of Common.dbound (0.0). */ if (L->is_ll) PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in L"); else PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in D"); break; default: PyErr_Warn(PyExc_UserWarning, ""); } if (L->minor<n) { CHOL(free_factor)(&L, &Common); PY_ERR(PyExc_ArithmeticError, "singular matrix"); } if (!(Bc = create_matrix(B))) { CHOL(free_factor)(&L, &Common); return PyErr_NoMemory(); } Xc = CHOL(spsolve)(0, L, Bc, &Common); free_matrix(Bc); CHOL(free_factor)(&L, &Common); if (Common.status != CHOLMOD_OK){ CHOL(free_sparse)(&Xc, &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else PY_ERR(PyExc_ValueError, "solve step failed"); } if (!(X = SpMatrix_New(Xc->nrow, Xc->ncol, ((int_t*)Xc->p)[Xc->ncol], SP_ID(A)))) { CHOL(free_sparse)(&Xc, &Common); return PyErr_NoMemory(); } memcpy(SP_COL(X), (int_t *) Xc->p, (Xc->ncol+1)*sizeof(int_t)); memcpy(SP_ROW(X), (int_t *) Xc->i, ((int_t *) Xc->p)[Xc->ncol]*sizeof(int_t)); memcpy(SP_VAL(X), (double *) Xc->x, ((int_t *) Xc->p)[Xc->ncol]*E_SIZE[SP_ID(X)]); CHOL(free_sparse)(&Xc, &Common); return (PyObject *) X; }
static int set_options(void) { int_t pos=0; PyObject *param, *key, *value; char err_str[100]; #if PY_MAJOR_VERSION < 3 char *keystr; #endif CHOL(defaults)(&Common); Common.print = 0; Common.supernodal = 2; if (!(param = PyObject_GetAttrString(cholmod_module, "options")) || ! PyDict_Check(param)) { PyErr_SetString(PyExc_AttributeError, "missing cholmod.options" "dictionary"); return 0; } while (PyDict_Next(param, &pos, &key, &value)) #if PY_MAJOR_VERSION >= 3 if (PyUnicode_Check(key)) { const char *keystr = _PyUnicode_AsString(key); if (!strcmp("supernodal", keystr) && PyLong_Check(value)) Common.supernodal = (int) PyLong_AsLong(value); else if (!strcmp("print", keystr) && PyLong_Check(value)) Common.print = (int) PyLong_AsLong(value); else if (!strcmp("nmethods", keystr) && PyLong_Check(value)) Common.nmethods = (int) PyLong_AsLong(value); else if (!strcmp("postorder", keystr) && PyBool_Check(value)) Common.postorder = (int) PyLong_AsLong(value); else if (!strcmp("dbound", keystr) && PyFloat_Check(value)) Common.dbound = (double) PyFloat_AsDouble(value); else { sprintf(err_str, "invalid value for CHOLMOD parameter:" \ " %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); Py_DECREF(param); return 0; } } #else if ((keystr = PyString_AsString(key))) { if (!strcmp("supernodal", keystr) && PyInt_Check(value)) Common.supernodal = (int) PyInt_AsLong(value); else if (!strcmp("print", keystr) && PyInt_Check(value)) Common.print = (int) PyInt_AsLong(value); else if (!strcmp("nmethods", keystr) && PyInt_Check(value)) Common.nmethods = (int) PyInt_AsLong(value); else if (!strcmp("postorder", keystr) && PyBool_Check(value)) Common.postorder = (int) PyInt_AsLong(value); else if (!strcmp("dbound", keystr) && PyFloat_Check(value)) Common.dbound = (double) PyFloat_AsDouble(value); else { sprintf(err_str, "invalid value for CHOLMOD parameter:" \ " %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); Py_DECREF(param); return 0; } } #endif Py_DECREF(param); return 1; }
static PyObject* linsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; matrix *B, *P=NULL; int i, n, nnz, oB=0, ldB=0, nrhs=-1; cholmod_sparse *Ac=NULL; cholmod_factor *L=NULL; cholmod_dense *x=NULL, *b=NULL; void *b_old; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo='L'; char *kwlist[] = {"A", "B", "p", "uplo", "nrhs", "ldB", "offsetB", NULL}; if (!set_options()) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OCiii", kwlist, &A, &B, &P, &uplo_, &nrhs, &ldB, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociii", kwlist, &A, &B, &P, &uplo, &nrhs, &ldB, &oB)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a sparse matrix"); n = SP_NROWS(A); nnz = SP_NNZ(A); if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A)) PY_ERR_TYPE("B must be a dense matrix of the same numerical " "type as A"); if (nrhs < 0) nrhs = MAT_NCOLS(B); if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldB == 0) ldB = MAX(1,MAT_NROWS(B)); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B"); if (P) { if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p"); if (MAT_LGT(P) != n) err_buf_len("p"); if (!CHOL(check_perm)(P->buffer, n, n, &Common)) PY_ERR(PyExc_ValueError, "not a valid permutation"); } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); L = CHOL(analyze_p)(Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common); if (Common.status != CHOLMOD_OK){ free_matrix(Ac); CHOL(free_sparse)(&Ac, &Common); CHOL(free_factor)(&L, &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else { PyErr_SetString(PyExc_ValueError, "symbolic factorization " "failed"); return NULL; } } CHOL(factorize) (Ac, L, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status < 0) { CHOL(free_factor)(&L, &Common); switch (Common.status) { case CHOLMOD_OUT_OF_MEMORY: return PyErr_NoMemory(); default: PyErr_SetString(PyExc_ValueError, "factorization " "failed"); return NULL; } } if (Common.status > 0) switch (Common.status) { case CHOLMOD_NOT_POSDEF: PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", L->minor)); CHOL(free_factor)(&L, &Common); return NULL; break; case CHOLMOD_DSMALL: /* This never happens unless we change the default value * of Common.dbound (0.0). */ if (L->is_ll) PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in L"); else PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in D"); break; default: PyErr_Warn(PyExc_UserWarning, ""); } if (L->minor<n) { CHOL(free_factor)(&L, &Common); PY_ERR(PyExc_ArithmeticError, "singular matrix"); } b = CHOL(allocate_dense)(n, 1, n, (MAT_ID(B) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX) , &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) { CHOL(free_factor)(&L, &Common); CHOL(free_dense)(&b, &Common); return PyErr_NoMemory(); } b_old = b->x; for (i=0; i<nrhs; i++) { b->x = MAT_BUF(B) + (i*ldB + oB)*E_SIZE[MAT_ID(B)]; x = CHOL(solve) (CHOLMOD_A, L, b, &Common); if (Common.status != CHOLMOD_OK){ PyErr_SetString(PyExc_ValueError, "solve step failed"); CHOL(free_factor)(&L, &Common); b->x = b_old; CHOL(free_dense)(&b, &Common); CHOL(free_dense)(&x, &Common); return NULL; } memcpy(b->x, x->x, SP_NROWS(A)*E_SIZE[MAT_ID(B)]); CHOL(free_dense)(&x, &Common); } b->x = b_old; CHOL(free_dense)(&b, &Common); CHOL(free_factor)(&L, &Common); return Py_BuildValue(""); }
static PyObject* spsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *B, *X=NULL; cholmod_sparse *Bc=NULL, *Xc=NULL; PyObject *F; cholmod_factor *L; int n, sys=0; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif char *kwlist[] = {"F", "B", "sys", NULL}; int sysvalues[] = {CHOLMOD_A, CHOLMOD_LDLt, CHOLMOD_LD, CHOLMOD_DLt, CHOLMOD_L, CHOLMOD_Lt, CHOLMOD_D, CHOLMOD_P, CHOLMOD_Pt }; if (!set_options()) return NULL; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|i", kwlist, &F, &B, &sys)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); L = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); L = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif if (L->xtype == CHOLMOD_PATTERN) PY_ERR(PyExc_ValueError, "called with symbolic factor"); n = L->n; if (L->minor<n) PY_ERR(PyExc_ArithmeticError, "singular matrix"); if (sys < 0 || sys > 8) PY_ERR(PyExc_ValueError, "invalid value for sys"); if (!SpMatrix_Check(B) || (SP_ID(B) == DOUBLE && L->xtype == CHOLMOD_COMPLEX) || (SP_ID(B) == COMPLEX && L->xtype == CHOLMOD_REAL)) PY_ERR_TYPE("B must a sparse matrix of the same " "numerical type as F"); if (SP_NROWS(B) != n) PY_ERR(PyExc_ValueError, "incompatible dimensions for B"); if (!(Bc = create_matrix(B))) return PyErr_NoMemory(); Xc = CHOL(spsolve)(sysvalues[sys], L, Bc, &Common); free_matrix(Bc); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); if (Common.status != CHOLMOD_OK) PY_ERR(PyExc_ValueError, "solve step failed"); if (!(X = SpMatrix_New(Xc->nrow, Xc->ncol, ((int_t*)Xc->p)[Xc->ncol], (L->xtype == CHOLMOD_REAL ? DOUBLE : COMPLEX)))) { CHOL(free_sparse)(&Xc, &Common); return PyErr_NoMemory(); } memcpy(SP_COL(X), Xc->p, (Xc->ncol+1)*sizeof(int_t)); memcpy(SP_ROW(X), Xc->i, ((int_t *)Xc->p)[Xc->ncol]*sizeof(int_t)); memcpy(SP_VAL(X), Xc->x, ((int_t *) Xc->p)[Xc->ncol]*E_SIZE[SP_ID(X)]); CHOL(free_sparse)(&Xc, &Common); return (PyObject *) X; }
static PyObject* solve(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *B; PyObject *F; int i, n, oB=0, ldB=0, nrhs=-1, sys=0; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif char *kwlist[] = {"F", "B", "sys", "nrhs", "ldB", "offsetB", NULL}; int sysvalues[] = { CHOLMOD_A, CHOLMOD_LDLt, CHOLMOD_LD, CHOLMOD_DLt, CHOLMOD_L, CHOLMOD_Lt, CHOLMOD_D, CHOLMOD_P, CHOLMOD_Pt }; if (!set_options()) return NULL; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, &F, &B, &sys, &nrhs, &ldB, &oB)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); cholmod_factor *L = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); cholmod_factor *L = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif if (L->xtype == CHOLMOD_PATTERN) PY_ERR(PyExc_ValueError, "called with symbolic factor"); n = L->n; if (L->minor<n) PY_ERR(PyExc_ArithmeticError, "singular matrix"); if (sys < 0 || sys > 8) PY_ERR(PyExc_ValueError, "invalid value for sys"); if (!Matrix_Check(B) || MAT_ID(B) == INT || (MAT_ID(B) == DOUBLE && L->xtype == CHOLMOD_COMPLEX) || (MAT_ID(B) == COMPLEX && L->xtype == CHOLMOD_REAL)) PY_ERR_TYPE("B must a dense matrix of the same numerical " "type as F"); if (nrhs < 0) nrhs = MAT_NCOLS(B); if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldB == 0) ldB = MAX(1,MAT_NROWS(B)); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B"); cholmod_dense *x; cholmod_dense *b = CHOL(allocate_dense)(n, 1, n, (MAT_ID(B) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); void *b_old = b->x; for (i=0; i<nrhs; i++){ b->x = MAT_BUF(B) + (i*ldB + oB)*E_SIZE[MAT_ID(B)]; x = CHOL(solve) (sysvalues[sys], L, b, &Common); if (Common.status != CHOLMOD_OK){ PyErr_SetString(PyExc_ValueError, "solve step failed"); CHOL(free_dense)(&x, &Common); CHOL(free_dense)(&b, &Common); return NULL; } memcpy(b->x, x->x, n*E_SIZE[MAT_ID(B)]); CHOL(free_dense)(&x, &Common); } b->x = b_old; CHOL(free_dense)(&b, &Common); return Py_BuildValue(""); }
static PyObject* numeric(PyObject *self, PyObject *args) { spmatrix *A; PyObject *F; cholmod_factor *Lc; cholmod_sparse *Ac = NULL; char uplo; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif if (!set_options()) return NULL; if (!PyArg_ParseTuple(args, "OO", &A, &F)) return NULL; if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a sparse matrix"); #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr) PY_ERR_TYPE("F is not a CHOLMOD factor"); #endif if (SP_ID(A) == DOUBLE){ if (!strcmp(descr, "CHOLMOD FACTOR D L")) uplo = 'L'; else if (!strcmp(descr, "CHOLMOD FACTOR D U")) uplo = 'U'; else PY_ERR_TYPE("F is not the CHOLMOD factor of a 'd' matrix"); } else { if (!strcmp(descr, "CHOLMOD FACTOR Z L")) uplo = 'L'; else if (!strcmp(descr, "CHOLMOD FACTOR Z U")) uplo = 'U'; else PY_ERR_TYPE("F is not the CHOLMOD factor of a 'z' matrix"); } #if PY_MAJOR_VERSION >= 3 Lc = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else Lc = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); CHOL(factorize) (Ac, Lc, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status < 0) switch (Common.status) { case CHOLMOD_OUT_OF_MEMORY: return PyErr_NoMemory(); default: PyErr_SetString(PyExc_ValueError, "factorization failed"); return NULL; } if (Common.status > 0) switch (Common.status) { case CHOLMOD_NOT_POSDEF: PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", Lc->minor)); return NULL; break; case CHOLMOD_DSMALL: /* This never happens unless we change the default value * of Common.dbound (0.0). */ if (Lc->is_ll) PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "\ "elements in L"); else PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "\ "elements in D"); break; default: PyErr_Warn(PyExc_UserWarning, ""); } return Py_BuildValue(""); }
static PyObject* symbolic(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; cholmod_sparse *Ac = NULL; cholmod_factor *L; matrix *P=NULL; #if PY_MAJOR_VERSION >= 3 int uplo_='L'; #endif char uplo='L'; int n; char *kwlist[] = {"A", "p", "uplo", NULL}; if (!set_options()) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OC", kwlist, &A, &P, &uplo_)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|Oc", kwlist, &A, &P, &uplo)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a square sparse matrix"); n = SP_NROWS(A); if (P) { if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p"); if (MAT_LGT(P) != n) err_buf_len("p"); if (!CHOL(check_perm)(P->buffer, n, n, &Common)) PY_ERR(PyExc_ValueError, "p is not a valid permutation"); } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); L = CHOL(analyze_p)(Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status != CHOLMOD_OK){ if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else{ PyErr_SetString(PyExc_ValueError, "symbolic factorization " "failed"); return NULL; } } #if PY_MAJOR_VERSION >= 3 return (PyObject *) PyCapsule_New((void *) L, SP_ID(A)==DOUBLE ? (uplo == 'L' ? "CHOLMOD FACTOR D L" : "CHOLMOD FACTOR D U") : (uplo == 'L' ? "CHOLMOD FACTOR Z L" : "CHOLMOD FACTOR Z U"), (PyCapsule_Destructor) &cvxopt_free_cholmod_factor); #else return (PyObject *) PyCObject_FromVoidPtrAndDesc((void *) L, SP_ID(A)==DOUBLE ? (uplo == 'L' ? "CHOLMOD FACTOR D L" : "CHOLMOD FACTOR D U") : (uplo == 'L' ? "CHOLMOD FACTOR Z L" : "CHOLMOD FACTOR Z U"), cvxopt_free_cholmod_factor); #endif }
static void cvxopt_free_cholmod_factor(void *L, void *descr) { CHOL(free_factor) ((cholmod_factor **) &L, &Common) ; }
static void cvxopt_free_cholmod_factor(void *L) { void *Lptr = PyCapsule_GetPointer(L, PyCapsule_GetName(L)); CHOL(free_factor) ((cholmod_factor **) &Lptr, &Common); }
static void free_matrix(cholmod_sparse *A) { A->x = NULL; A->i = NULL; CHOL(free_sparse)(&A, &Common); }
mlgpStatus_t MLGP_LIKELIHOOD_CPU ( FLOAT* nll, MATRIX_T X, VECTOR_T y, INF_T inf, MEAN_T mean, COV_T cov, LIK_T lik, mlgpWorkspace_t* workspace, mlgpOptions_t options ) { /* Exact inference with Gaussian Likelihood */ /* This function computes the negative log marginal likelihood (nll) * and its derivatives with respect to the mean, covariance and likelihood * function hyperparameters. * * Arguments: * - nll : Pointer to a FLOAT to store the negative log * marginal likelihood * * - X : MATRIX_T containing the matrix of training inputs. * Each row represents one input vector. Column major format. * * - y : VECTOR_T containing the vector of training targets. * * - inf : mlgpInf_t specifying the inference method to be used * (currently only the exact inference method available). * * - mean : mlgpMean_t specifying the mean function and its parameters * * - cov : mlgpCov_t specifying the covaraince function and its * parameters * * - lik : mlgpLik_t specifying the likelihood function and its * parameters (currently only the Gaussian likelihood * avaialble). * * - workspace : mlgpWorkspace_t containing the pointer to pointer for * the working memory. If the NOWORKSPACE flag is set in * options.opts, then this function takes care of memory * allocation entirely. If the CREATEWORKSPACE flag is * set, this function only allocates the required working * memory in workspace->ws[0] (based on the parameters passed * in) and returns without performing any computation. * * If the SAVE flags is set, then workspace->ws[1] will * contain a pointer to a N*N + N block of memory containing * the vector (K^-1)*(y-m) and the Cholesky factor of the * covariance matrix K (to use for prediction). * Note for this workspace->ws will need to have at least two * pointers worth of memory allocated to it. * * - options : mlgpOptions_t specifying the options for the computation. * Possible options are * - CREATEWORKSPACE (as described above) * - NOWORKSPACE (as described above) * - PACKED uses packed storage for symmetric matrices * - SAVE (as described above) */ unsigned N, dim; unsigned sizeK, memoryNeeded; unsigned np_cov, np_mean; ptrdiff_t shift; MATRIX_T K, dKdTheta1, dKdTheta2; VECTOR_T ymm, Kinvy; FLOAT sig_n2; mlgpOptions_t int_opts; N = X.nrows; dim = X.ncols; sizeK = (options.opts&PACKED) ? (N*(N+1))/2 : N*N; memoryNeeded = 3*sizeK + 2*N; /* Compute and assign working memory needed */ if(options.opts&CREATEWORKSPACE || options.opts&NOWORKSPACE){ if(options.opts&SAVE){ workspace->ws = malloc(2*sizeof(FLOAT*)); workspace->size = 2; workspace->allocated = 0x3u; }else{ workspace->ws = malloc(sizeof(FLOAT*)); workspace->size = 1; workspace->allocated = 0x1u; } workspace->ws[0] = malloc(memoryNeeded*sizeof(FLOAT)); if(options.opts&SAVE){ workspace->ws[1] = malloc((N*N+N)*sizeof(FLOAT)); } if(options.opts&CREATEWORKSPACE){ return mlgpSuccess; } } K = MLGP_CREATEMATRIXNOMALLOC(N,N); dKdTheta1 = MLGP_CREATEMATRIXNOMALLOC(N,N); dKdTheta2 = MLGP_CREATEMATRIXNOMALLOC(N,N); ymm = MLGP_CREATEVECTORNOMALLOC(N); Kinvy = MLGP_CREATEVECTORNOMALLOC(N); shift = 0; K.m = (FLOAT*)workspace->ws[0]+shift; shift+=sizeK; // N*N - covariance matrix dKdTheta1.m = (FLOAT*)workspace->ws[0]+shift; shift+=sizeK; // N*N - covariance derivatives dKdTheta2.m = (FLOAT*)workspace->ws[0]+shift; shift+=sizeK; // N*N - covariance derivatives ymm.v = (FLOAT*)workspace->ws[0]+shift; shift+=N; // N - y-m Kinvy.v = (FLOAT*)workspace->ws[0]+shift; shift+=N; // N - (K^-1)*y /* ymm contains y */ MLGP_COPY(N,y.v,1,ymm.v,1); /* apply mean function, ymm contains y-m */ int_opts.opts = _SUBMEAN; MLGP_MEAN(ymm,X,mean,ymm,0,int_opts); /* copy y-m into Kinvy */ MLGP_COPY(N,ymm.v,1,Kinvy.v,1); /* generate the covariance matrix in K */ int_opts.opts = _SYMM; if(options.opts&PACKED){ int_opts.opts|=_PACKED; } MLGP_COV(K,X,X,cov,K,0,int_opts); /* cache K in dKdTheta2 for derivatives computation */ if(options.opts&PACKED){ MLGP_COPY((N*(N+1))/2,K.m,1,dKdTheta2.m,1); }else{ MLGP_COPY(N*N,K.m,1,dKdTheta2.m,1); } /* add noise term to the diagonal */ sig_n2 = exp(2.*lik.params[0]); if(options.opts&PACKED){ for(unsigned i=0;i<N;i++){ K.m[i+(i*(i+1))/2] += sig_n2; } }else{ MLGP_AXPY(N,1.,&sig_n2,0,K.m,N+1); } /* Cholesky decomposition K = LL^T */ /* solve K(Kinvy) = y for Kinvy using L */ if(options.opts&PACKED){ CHOL_PACKED(K); SOLVE_CHOL_PACKED_ONE(K,Kinvy); }else{ CHOL(K); SOLVE_CHOL_ONE(K,Kinvy); } /* first term in nll = 0.5*y'*(K^-1)*y */ *nll = 0.5*MLGP_DOT(N,ymm.v,1,Kinvy.v,1); /* second term in nll = 0.5*log(det(K)) * = 0.5*log(det(LL')) = 0.5*log(det(L)^2) = log(det(L))*/ if(options.opts&PACKED){ *nll += LOG_DET_TR_PACKED(K); }else{ *nll += LOG_DET_TR(K); } /* third term in nll = (N/2)*log(2*pi) */ *nll += N*HALFLOG2PI; if(options.opts&SAVE){ MLGP_COPY(N,Kinvy.v,1,workspace->ws[1],1); MLGP_COPY(N*N,K.m,1,workspace->ws[1]+N,1); } /* derivatives */ if(!(options.opts&NODERIVATIVES)){ /* precompute Q = (K^-1) - Kinvy'*Kinvy (stored in K) */ if(options.opts&PACKED){ INV_CHOL_PACKED(K); MLGP_SPR('U',N,-1.,Kinvy.v,1,K.m); }else{ INV_CHOL(K); MLGP_GEMM('N','N',N,N,1,-1.,Kinvy.v,N,Kinvy.v,1,1.,K.m,N); } /* get number of covariance function parameters */ np_cov = MLGP_NPARAMS_COV(cov,dim); /* covariance function options flag for derivatives computation */ int_opts.opts = _SYMM|_DERIVATIVES|_PRECOMPUTE; if(options.opts&PACKED){ int_opts.opts|=_PACKED; } /* iterate through covariance parameters and compute derivatives for each */ for(unsigned p_i=0;p_i<np_cov;p_i++){ MLGP_COV(dKdTheta2,X,X,cov,dKdTheta1,p_i,int_opts); if(options.opts&PACKED){ // elementwise product of Q and dKdTheta1 = trace(Q*dKdTheta1) cov.dparams[p_i] = MLGP_DOT((N*(N+1))/2,dKdTheta1.m,1,K.m,1); // subtract duplicates from using the diagonal twice for(unsigned i=0;i<N;i++){ cov.dparams[p_i] -= K.m[i+(i*(i+1))/2]*dKdTheta1.m[i+(i*(i+1))/2]/2; } }else{ // elementwise product of Q and dKdTheta1 = trace(Q*dKdTheta1) cov.dparams[p_i] = MLGP_DOT(N*N,dKdTheta1.m,1,K.m,1)/2; } } /* get number of mean parameters */ np_mean = MLGP_NPARAMS_MEAN(mean,dim); /* iterate through mean parameters and compute derivatives for each */ /* using ymm as memory to hold mean derivatives */ int_opts.opts = _DERIVATIVES; for(unsigned p_i=0;p_i<np_mean;p_i++){ MLGP_MEAN(ymm,X,mean,ymm,p_i,int_opts); mean.dparams[p_i] = -MLGP_DOT(N,Kinvy.v,1,ymm.v,1); } /* derivative wrt gaussian noise parameter = sig_n*tr(Q) */ if(options.opts&PACKED){ lik.dparams[0] = 0; for(unsigned i=0;i<N;i++){ lik.dparams[0] += K.m[i+(i*(i+1))/2]*sig_n2; } }else{ lik.dparams[0] = MLGP_DOT(N,K.m,N+1,&sig_n2,0); } if(options.opts&NOWORKSPACE){ free(workspace->ws[0]); workspace->allocated&=(~0x1u); } } return mlgpSuccess; }