The API can be used to extend CVXOPT with interfaces to external C routines
and libraries. A C program that creates or manipulates the dense or sparse
matrix objects defined in CVXOPT must include the cvxopt.h
header
file in the src
directory of the distribution.
Before the C API can be used in an extension module it must be initialized
by calling the macro import_cvxopt
. As an example we show the
module initialization from the cvxopt.blas
module, which itself uses
the API:
#if PY_MAJOR_VERSION >= 3
static PyModuleDef blas_module = {
PyModuleDef_HEAD_INIT,
"blas",
blas__doc__,
-1,
blas_functions,
NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC PyInit_blas(void)
{
PyObject *m;
if (!(m = PyModule_Create(&blas_module))) return NULL;
if (import_cvxopt() < 0) return NULL;
return m;
}
#else
PyMODINIT_FUNC initblas(void)
{
PyObject *m;
m = Py_InitModule3("cvxopt.blas", blas_functions, blas__doc__);
if (import_cvxopt() < 0) return ;
}
#endif
Dense Matrices
As can be seen from the header file cvxopt.h
, a matrix
is
essentially a structure with four fields. The fields nrows
and
ncols
are two integers that specify the dimensions. The
id
field controls the type of the matrix and can have values
DOUBLE
, INT
, and COMPLEX
. The buffer
field is an array that contains the matrix elements stored contiguously in
column-major order.
The following C functions can be used to create matrices.
-
matrix *Matrix_New(int nrows, int ncols, int id)
Returns a matrix
object of type id with nrows rows and
ncols columns. The elements of the matrix are uninitialized.
-
matrix *Matrix_NewFromMatrix(matrix *src, int id)
Returns a copy of the matrix src converted to type id. The
following type conversions are allowed: 'i'
to 'd'
,
'i'
to 'z'
, and 'd'
to 'z'
.
-
matrix *Matrix_NewFromSequence(PyListObject *x, int id)
Creates a matrix of type id from the Python sequence type x. The
returned matrix has size (len(x), 1)
. The size can be changed
by modifying the nrows
and ncols
fields of the
returned matrix.
To illustrate the creation and manipulation of dense matrices (as well as
the Python C API), we show the code for the cvxopt.uniform
function
described in the section Randomly Generated Matrices.
PyObject * uniform(PyObject *self, PyObject *args, PyObject *kwrds)
{
matrix *obj;
int i, nrows, ncols = 1;
double a = 0, b = 1;
char *kwlist[] = {"nrows", "ncols", "a", "b", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist,
&nrows, &ncols, &a, &b)) return NULL;
if ((nrows<0) || (ncols<0)) {
PyErr_SetString(PyExc_TypeError, "dimensions must be non-negative");
return NULL;
}
if (!(obj = Matrix_New(nrows, ncols, DOUBLE)))
return PyErr_NoMemory();
for (i = 0; i < nrows*ncols; i++)
MAT_BUFD(obj)[i] = Uniform(a,b);
return (PyObject *)obj;
}
Sparse Matrices
Sparse matrices are stored in compressed column storage (CCS) format. For
a general nrows by ncols sparse matrix with nnz nonzero entries this
means the following. The sparsity pattern and the nonzero values are
stored in three fields:
values
An array of floating-point numbers of length nnz with the
nonzero entries of the matrix stored columnwise.
rowind
An array of integers of length nnz containing the row indices of
the nonzero entries, stored in the same order as values
.
colptr
An array of integers of length ncols + 1 with for each column of the
matrix the index of the first element in values
from that
column. More precisely, colptr[0]
is 0
, and for
k = 0, 1, …, ncols - 1, colptr[k+1]
is equal to
colptr[k]
plus the number of nonzeros in column k of the
matrix. Thus, colptr[ncols]
is equal to nnz, the number of
nonzero entries.
For example, for the matrix
System Message: WARNING/2 (A=\left [\begin{array}{cccc}
1 & 0 & 0 & 5\\
2 & 0 & 4 & 0\\
0 & 0 & 0 & 6\\
3 & 0 & 0 & 0
\end{array}\right])
latex exited with error
[stderr]
kpathsea: Running mktexfmt latex.fmt
mktexfmt: mktexfmt is using the following fmtutil.cnf files (in precedence order):
mktexfmt: /usr/share/texmf-dist/web2c/fmtutil.cnf
mktexfmt: mktexfmt is using the following fmtutil.cnf file for writing changes:
mktexfmt: /usr/src/.texlive2021/texmf-config/web2c/fmtutil.cnf
mktexfmt [INFO]: writing formats under /usr/src/.texlive2021/texmf-var/web2c
mktexfmt [INFO]: --- remaking latex with pdftex
mktexfmt: running `pdftex -ini -jobname=latex -progname=latex -translate-file=cp227.tcx *latex.ini' ...
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/Mageia) (INITEX)
restricted \write18 enabled.
(/usr/share/texmf-dist/web2c/cp227.tcx)
entering extended mode
(/usr/share/texmf-dist/tex/latex/latexconfig/latex.ini
(/usr/share/texmf-dist/tex/generic/config/pdftexconfig.tex)
(/usr/share/texmf-dist/tex/latex/base/latex.ltx
(/usr/share/texmf-dist/tex/latex/base/texsys.cfg)
./texsys.aux found
\@currdir set to: ./.
Assuming \openin and \input
have the same search path.
Defining UNIX/DOS style filename parser.
catcodes, registers, parameters,
LaTeX2e <2020-10-01> patch level 4
(/usr/share/texmf-dist/tex/latex/l3kernel/expl3.ltx
(/usr/share/texmf-dist/tex/latex/l3kernel/expl3-code.tex
! LaTeX3 Error: File 'UnicodeData.txt' not found.
For immediate help type H <return>.
...
l.30209 }
(/usr/share/texmf-dist/tex/latex/l3kernel/l3deprecation.def)))
(/usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse.ltx
(/usr/share/texmf-dist/tex/latex/l3packages/xparse/xparse-generic.tex)) hacks,
control, par, spacing, files, font encodings, lengths,
====================================
Local config file fonttext.cfg used
====================================
(/usr/share/texmf-dist/tex/latex/base/fonttext.cfg
(/usr/share/texmf-dist/tex/latex/base/fonttext.ltx
=== Don't modify this file, use a .cfg file instead ===
(/usr/share/texmf-dist/tex/latex/base/omlenc.def)
(/usr/share/texmf-dist/tex/latex/base/omsenc.def)
(/usr/share/texmf-dist/tex/latex/base/ot1enc.def)
(/usr/share/texmf-dist/tex/latex/base/t1enc.def)
(/usr/share/texmf-dist/tex/latex/base/ts1enc.def)
(/usr/share/texmf-dist/tex/latex/base/ts1cmr.fd)
(/usr/share/texmf-dist/tex/latex/base/t1cmr.fd)
(/usr/share/texmf-dist/tex/latex/base/ot1cmr.fd)
(/usr/share/texmf-dist/tex/latex/base/ot1cmss.fd)
(/usr/share/texmf-dist/tex/latex/base/ot1cmtt.fd)))
====================================
Local config file fontmath.cfg used
====================================
(/usr/share/texmf-dist/tex/latex/base/fontmath.cfg
(/usr/share/texmf-dist/tex/latex/base/fontmath.ltx
=== Don't modify this file, use a .cfg file instead ===
(/usr/share/texmf-dist/tex/latex/base/omlcmm.fd)
(/usr/share/texmf-dist/tex/latex/base/omscmsy.fd)
(/usr/share/texmf-dist/tex/latex/base/omxcmex.fd)
(/usr/share/texmf-dist/tex/latex/base/ucmr.fd)))
====================================
Local config file preload.cfg used
=====================================
(/usr/share/texmf-dist/tex/latex/base/preload.cfg
(/usr/share/texmf-dist/tex/latex/base/preload.ltx)) page nos., x-ref,
environments, center, verbatim, math definitions, boxes, title, sectioning,
contents, floats, footnotes, index, bibliography, output,
===========================================
Local configuration file hyphen.cfg used
===========================================
(/usr/share/texmf-dist/tex/generic/babel/hyphen.cfg
(/usr/share/texmf-dist/tex/generic/hyphen/hyphen.tex)
(/usr/share/texmf-dist/tex/generic/hyphen/dumyhyph.tex)
(/usr/share/texmf-dist/tex/generic/hyphen/zerohyph.tex)
(/usr/share/texmf-dist/tex/generic/dehyph-exptl/dehypht-x-2021-02-26.tex
dehyph-exptl: using an 8-bit TeX engine.
(/usr/share/texmf-dist/tex/generic/dehyph-exptl/dehypht-x-2021-02-26.pat
German Hyphenation Patterns (Traditional Orthography) `dehypht-x' 2021-02-26 (W
L))) (/usr/share/texmf-dist/tex/generic/dehyph-exptl/dehyphn-x-2021-02-26.tex
dehyph-exptl: using an 8-bit TeX engine.
(/usr/share/texmf-dist/tex/generic/dehyph-exptl/dehyphn-x-2021-02-26.pat
German Hyphenation Patterns (Reformed Orthography, 2006) `dehyphn-x' 2021-02-26
(WL))) (/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-af.tex
EC Afrikaans hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-af.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-grc.tex
Hyphenation patterns for Ancient Greek
(/usr/share/texmf-dist/tex/generic/hyphen/grahyph5.tex
Hyphenation patterns for Ancient Greek))
(/usr/share/texmf-dist/tex/generic/hyphen/ibyhyph.tex
Greek hyphenation patterns for Ibycus encoding, v3.0)
(/usr/share/texmf-dist/tex/generic/hyphen/zerohyph.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-hy.tex
No Armenian hyphenation patterns - only for Unicode engines)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-eu.tex
EC Basque hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-eu.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-be.tex
T2A Belarusian hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-t2a.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-be.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-bg.tex
T2A Bulgarian hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-t2a.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-bg.tex
Bulgarian hyphenation patterns (options: --safe-morphology --standalone-tex, ve
rsion 21 October 2017)))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-ca.tex
EC Catalan hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-ca.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-zh-latn-pinyin.t
ex EC Pinyin Hyphenation Patterns (with tone markers) 2018-11-25 (WL)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/ptex/hyph-zh-latn-pinyin.
ec.tex)) (/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-cu.tex
No Church Slavonic hyphenation patterns - only for Unicode engines)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-cop.tex
Coptic hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex-8bit/copthyph.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-hr.tex
EC Croatian hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-hr.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-cs.tex
EC Czech hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-cs.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-da.tex
EC Danish hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-da.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-nl.tex
EC Dutch hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-nl.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-en-gb.tex
ASCII Hyphenation patterns for British English
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-en-gb.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-en-us.tex
ASCII Hyphenation patterns for American English
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-en-us.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-eo.tex
IL3 Esperanto hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-il3.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-eo.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-et.tex
EC Estonian hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-et.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-mul-ethi.tex
No Pan-Ethiopic hyphenation patterns - only for Unicode engines)
(/usr/share/texmf-dist/tex/generic/hyphen/zerohyph.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-fi.tex
EC Finnish hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-fi.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-fi-x-school.tex
EC Finnish hyphenation patterns for school
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-fi-x-school.tex)
) (/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-fr.tex
EC French hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-fr.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-fur.tex
EC Friulan hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-fur.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-gl.tex
EC Galician hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-ec.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-gl.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-ka.tex
T8M Georgian hyphenation patterns
(/usr/share/texmf-dist/tex/generic/hyph-utf8/conversions/conv-utf8-t8m.tex)
(/usr/share/texmf-dist/tex/generic/hyph-utf8/patterns/tex/hyph-ka.tex))
(/usr/share/texmf-dist/tex/generic/hyph-utf8/loadhyph/loadhyph-de-1901.tex
EC German hyphenation patterns (traditional orthography)
! I can't find file `dehypht.tex'.
l.29 \input dehypht.tex
(Press Enter to retry, or Control-D to exit)
Please type another input file name:
! Emergency stop.
l.29 \input dehypht.tex
No pages of output.
Transcript written on latex.log.
mktexfmt [INFO]: log file copied to: /usr/src/.texlive2021/texmf-var/web2c/pdftex/latex.log
mktexfmt [ERROR]: running `pdftex -ini -jobname=latex -progname=latex -translate-file=cp227.tcx *latex.ini >&2 </dev/null' return status: 1
mktexfmt [ERROR]: returning error due to option --strict
mktexfmt [INFO]: disabled formats: 5
mktexfmt [INFO]: not selected formats: 53
mktexfmt [INFO]: failed to build: 1 (pdftex/latex)
mktexfmt [INFO]: total formats: 59
mktexfmt [INFO]: exiting with status 1
[stdout]
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/Mageia) (preloaded format=latex)
restricted \write18 enabled.
I can't find the format file `latex.fmt'!
the elements of values
, rowind
, and colptr
are:
values
:1.0, 2.0, 3.0, 4.0, 5.0, 6.0
rowind
:0, 1,3, 1, 0, 2
colptr
:0, 3, 3, 4, 6.
It is crucial that for each column the row indices in rowind
are
sorted; the equivalent representation
values
:3.0, 2.0, 1.0, 4.0, 5.0, 6.0
rowind
:3, 1, 0, 1, 0, 2
colptr
:0, 3, 3, 4, 6
is not allowed (and will likely cause the program to crash).
The nzmax
field specifies the number of non-zero elements the
matrix can store. It is equal to the length of rowind
and
values
; this number can be larger that colptr[nrows]
,
but never less. This field makes it possible to preallocate a certain
amount of memory to avoid reallocations if the matrix is constructed
sequentially by filling in elements. In general the nzmax
field
can safely be ignored, however, since it will always be adjusted
automatically as the number of non-zero elements grows.
The id
field controls the type of the matrix and can have
values DOUBLE
and COMPLEX
.
Sparse matrices are created using the following functions from the API.
-
spmatrix *SpMatrix_New(int_t nrows, int_t ncols, int_t nzmax, int id)
Returns a sparse zero matrix with nrows rows and ncols columns.
nzmax is the number of elements that will be allocated (the length of
the values
and rowind
fields).
-
spmatrix *SpMatrix_NewFromMatrix(spmatrix *src, int id)
Returns a copy the sparse matrix var{src}.
-
spmatrix *SpMatrix_NewFromIJV(matrix *I, matrix *J, matrix *V, int_t nrows, int_t ncols, int id)
Creates a sparse matrix with nrows rows and ncols columns from a
triplet description. I and J must be integer matrices and V
either a double or complex matrix, or NULL
. If V is
NULL
the values of the entries in the matrix are undefined,
otherwise they are specified by V. Repeated entries in V are
summed. The number of allocated elements is given by nzmax, which is
adjusted if it is smaller than the required amount.
We illustrate use of the sparse matrix class by listing the source
code for the real
method, which returns the real part of
a sparse matrix:
static PyObject * spmatrix_real(spmatrix *self) {
if (SP_ID(self) != COMPLEX)
return (PyObject *)SpMatrix_NewFromMatrix(self, 0, SP_ID(self));
spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self),
SP_NNZ(self), DOUBLE);
if (!ret) return PyErr_NoMemory();
int i;
for (i=0; i < SP_NNZ(self); i++)
SP_VALD(ret)[i] = creal(SP_VALZ(self)[i]);
memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t));
memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t));
return (PyObject *)ret;
}