Coverage Report

Created: 2026-10-16 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/src/core/matrix.c
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>
4
   334 Harvard street, Cambridge, MA 02139 USA
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 2 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
19
   02110-1301 USA
20
21
*/
22
23
#include "igraph_matrix.h"
24
#include "igraph_types.h"
25
26
#define BASE_IGRAPH_REAL
27
#include "igraph_pmt.h"
28
#include "matrix.pmt"
29
#include "igraph_pmt_off.h"
30
#undef BASE_IGRAPH_REAL
31
32
#define BASE_INT
33
#include "igraph_pmt.h"
34
#include "matrix.pmt"
35
#include "igraph_pmt_off.h"
36
#undef BASE_INT
37
38
#define BASE_CHAR
39
#include "igraph_pmt.h"
40
#include "matrix.pmt"
41
#include "igraph_pmt_off.h"
42
#undef BASE_CHAR
43
44
#define BASE_BOOL
45
#include "igraph_pmt.h"
46
#include "matrix.pmt"
47
#include "igraph_pmt_off.h"
48
#undef BASE_BOOL
49
50
#define BASE_COMPLEX
51
#include "igraph_pmt.h"
52
#include "matrix.pmt"
53
#include "igraph_pmt_off.h"
54
#undef BASE_COMPLEX
55
56
/**
57
 * \ingroup matrix
58
 * \function igraph_matrix_complex_real
59
 * \brief Gives the real part of a complex matrix.
60
 *
61
 * \param m Pointer to a complex matrix.
62
 * \param real Pointer to an initialized matrix. The result will be stored here.
63
 * \return Error code.
64
 *
65
 * Time complexity: O(n),
66
 * n is the
67
 * number of elements in the matrix.
68
 */
69
70
igraph_error_t igraph_matrix_complex_real(const igraph_matrix_complex_t *m,
71
0
                               igraph_matrix_t *real) {
72
0
    igraph_int_t nrow = igraph_matrix_complex_nrow(m);
73
0
    igraph_int_t ncol = igraph_matrix_complex_ncol(m);
74
0
    IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol));
75
0
    IGRAPH_CHECK(igraph_vector_complex_real(&m->data, &real->data));
76
0
    return IGRAPH_SUCCESS;
77
0
}
78
79
/**
80
 * \ingroup matrix
81
 * \function igraph_matrix_complex_imag
82
 * \brief Gives the imaginary part of a complex matrix.
83
 *
84
 * \param m Pointer to a complex matrix.
85
 * \param imag Pointer to an initialized matrix. The result will be stored here.
86
 * \return Error code.
87
 *
88
 * Time complexity: O(n),
89
 * n is the
90
 * number of elements in the matrix.
91
 */
92
93
igraph_error_t igraph_matrix_complex_imag(const igraph_matrix_complex_t *m,
94
0
                               igraph_matrix_t *imag) {
95
0
    igraph_int_t nrow = igraph_matrix_complex_nrow(m);
96
0
    igraph_int_t ncol = igraph_matrix_complex_ncol(m);
97
0
    IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol));
98
0
    IGRAPH_CHECK(igraph_vector_complex_imag(&m->data, &imag->data));
99
0
    return IGRAPH_SUCCESS;
100
0
}
101
102
/**
103
 * \ingroup matrix
104
 * \function igraph_matrix_complex_realimag
105
 * \brief Gives the real and imaginary parts of a complex matrix.
106
 *
107
 * \param m Pointer to a complex matrix.
108
 * \param real Pointer to an initialized matrix. The real part will be stored here.
109
 * \param imag Pointer to an initialized matrix. The imaginary part will be stored here.
110
 * \return Error code.
111
 *
112
 * Time complexity: O(n),
113
 * n is the
114
 * number of elements in the matrix.
115
 */
116
117
igraph_error_t igraph_matrix_complex_realimag(const igraph_matrix_complex_t *m,
118
                                   igraph_matrix_t *real,
119
0
                                   igraph_matrix_t *imag) {
120
0
    igraph_int_t nrow = igraph_matrix_complex_nrow(m);
121
0
    igraph_int_t ncol = igraph_matrix_complex_ncol(m);
122
0
    IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol));
123
0
    IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol));
124
0
    IGRAPH_CHECK(igraph_vector_complex_realimag(&m->data, &real->data,
125
0
                 &imag->data));
126
0
    return IGRAPH_SUCCESS;
127
0
}
128
129
/**
130
 * \ingroup matrix
131
 * \function igraph_matrix_complex_create
132
 * \brief Creates a complex matrix from a real and imaginary part.
133
 *
134
 * \param m Pointer to an uninitialized complex matrix.
135
 * \param real Pointer to the real part of the complex matrix.
136
 * \param imag Pointer to the imaginary part of the complex matrix.
137
 * \return Error code.
138
 *
139
 * Time complexity: O(n),
140
 * n is the
141
 * number of elements in the matrix.
142
 */
143
144
igraph_error_t igraph_matrix_complex_create(igraph_matrix_complex_t *m,
145
                                 const igraph_matrix_t *real,
146
0
                                 const igraph_matrix_t *imag) {
147
0
    igraph_int_t nrowr = igraph_matrix_nrow(real);
148
0
    igraph_int_t ncolr = igraph_matrix_ncol(real);
149
0
    igraph_int_t nrowi = igraph_matrix_nrow(imag);
150
0
    igraph_int_t ncoli = igraph_matrix_ncol(imag);
151
152
0
    if (nrowr != nrowi || ncolr != ncoli) {
153
0
        IGRAPH_ERRORF("Dimensions of real (%" IGRAPH_PRId " by %" IGRAPH_PRId ") and "
154
0
                "imaginary (%" IGRAPH_PRId " by %" IGRAPH_PRId ") matrices must match.",
155
0
                IGRAPH_EINVAL, nrowr, ncolr, nrowi, ncoli);
156
0
    }
157
158
0
    IGRAPH_CHECK(igraph_matrix_complex_init(m, nrowr, ncolr));
159
160
0
    for (igraph_int_t i = 0; i < nrowr * ncolr; i++) {
161
0
        VECTOR(m->data)[i] = igraph_complex(VECTOR(real->data)[i], VECTOR(imag->data)[i]);
162
0
    }
163
164
0
    return IGRAPH_SUCCESS;
165
0
}
166
167
/**
168
 * \ingroup matrix
169
 * \function igraph_matrix_complex_create_polar
170
 * \brief Creates a complex matrix from a magnitude and an angle.
171
 *
172
 * \param m Pointer to an uninitialized complex matrix.
173
 * \param r Pointer to a real matrix containing magnitudes.
174
 * \param theta Pointer to a real matrix containing arguments (phase angles).
175
 * \return Error code.
176
 *
177
 * Time complexity: O(n),
178
 * n is the
179
 * number of elements in the matrix.
180
 */
181
182
igraph_error_t igraph_matrix_complex_create_polar(igraph_matrix_complex_t *m,
183
                                       const igraph_matrix_t *r,
184
0
                                       const igraph_matrix_t *theta) {
185
0
    igraph_int_t nrowr = igraph_matrix_nrow(r);
186
0
    igraph_int_t ncolr = igraph_matrix_ncol(r);
187
0
    igraph_int_t nrowt = igraph_matrix_nrow(theta);
188
0
    igraph_int_t ncolt = igraph_matrix_ncol(theta);
189
190
0
    if (nrowr != nrowt || ncolr != ncolt) {
191
0
        IGRAPH_ERRORF("Dimensions of magnitude (%" IGRAPH_PRId " by %" IGRAPH_PRId ") and "
192
0
                "angle (%" IGRAPH_PRId " by %" IGRAPH_PRId ") matrices must match.",
193
0
                IGRAPH_EINVAL, nrowr, ncolr, nrowt, ncolt);
194
0
    }
195
196
0
    IGRAPH_CHECK(igraph_matrix_complex_init(m, nrowr, ncolr));
197
198
0
    for (igraph_int_t i = 0; i < nrowr * ncolr; i++) {
199
0
        VECTOR(m->data)[i] = igraph_complex_polar(VECTOR(r->data)[i], VECTOR(theta->data)[i]);
200
0
    }
201
0
    return IGRAPH_SUCCESS;
202
0
}
203
204
/**
205
 * \function igraph_matrix_complex_all_almost_e
206
 * \brief Are all elements almost equal?
207
 *
208
 * Checks if the elements of two complex matrices are equal within a relative tolerance.
209
 *
210
 * \param lhs The first matrix.
211
 * \param rhs The second matrix.
212
 * \param eps Relative tolerance, see \ref igraph_complex_almost_equals() for details.
213
 * \return True if the two matrices are almost equal, false if there is at least
214
 *     one differing element or if the matrices are not of the same dimensions.
215
 */
216
igraph_bool_t igraph_matrix_complex_all_almost_e(igraph_matrix_complex_t *lhs,
217
                                                  igraph_matrix_complex_t *rhs,
218
0
                                                  igraph_real_t eps) {
219
0
    return lhs->ncol == rhs->ncol && lhs->nrow == rhs->nrow &&
220
0
            igraph_vector_complex_all_almost_e(&lhs->data, &rhs->data, eps);
221
0
}
222
223
224
/**
225
 * \function igraph_matrix_all_almost_e
226
 * \brief Are all elements almost equal?
227
 *
228
 * Checks if the elements of two matrices are equal within a relative tolerance.
229
 *
230
 * \param lhs The first matrix.
231
 * \param rhs The second matrix.
232
 * \param eps Relative tolerance, see \ref igraph_almost_equals() for details.
233
 * \return True if the two matrices are almost equal, false if there is at least
234
 *     one differing element or if the matrices are not of the same dimensions.
235
 */
236
igraph_bool_t igraph_matrix_all_almost_e(const igraph_matrix_t *lhs,
237
                                         const igraph_matrix_t *rhs,
238
0
                                         igraph_real_t eps) {
239
0
    return lhs->ncol == rhs->ncol && lhs->nrow == rhs->nrow &&
240
0
            igraph_vector_all_almost_e(&lhs->data, &rhs->data, eps);
241
0
}
242
243
244
/**
245
 * \function igraph_matrix_zapsmall
246
 * \brief Replaces small elements of a matrix by exact zeros.
247
 *
248
 * Matrix elements which are smaller in magnitude than the given absolute
249
 * tolerance will be replaced by exact zeros. The default tolerance
250
 * corresponds to two-thirds of the representable digits of \type igraph_real_t,
251
 * i.e. <code>DBL_EPSILON^(2/3)</code> which is approximately <code>10^-10</code>.
252
 *
253
 * \param m   The matrix to process, it will be changed in-place.
254
 * \param tol Tolerance value. Numbers smaller than this in magnitude will
255
 *            be replaced by zeros. Pass in zero to use the default tolerance.
256
 *            Must not be negative.
257
 * \return Error code.
258
 *
259
 * \sa \ref igraph_matrix_all_almost_e() and \ref igraph_almost_equals() to
260
 * perform comparisons with relative tolerances.
261
 */
262
0
igraph_error_t igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol) {
263
0
    return igraph_vector_zapsmall(&m->data, tol);
264
0
}
265
266
/**
267
 * \function igraph_matrix_complex_zapsmall
268
 * \brief Replaces small elements of a complex matrix by exact zeros.
269
 *
270
 * Similarly to \ref igraph_matrix_zapsmall(), small elements will be replaced
271
 * by zeros. The operation is performed separately on the real and imaginary
272
 * parts of the numbers. This way, complex numbers with a large real part and
273
 * tiny imaginary part will effectively be transformed to real numbers.
274
 * The default tolerance
275
 * corresponds to two-thirds of the representable digits of \type igraph_real_t,
276
 * i.e. <code>DBL_EPSILON^(2/3)</code> which is approximately <code>10^-10</code>.
277
 *
278
 * \param m   The matrix to process, it will be changed in-place.
279
 * \param tol Tolerance value. Real and imaginary parts smaller than this in
280
 *            magnitude will be replaced by zeros. Pass in zero to use the default
281
 *            tolerance. Must not be negative.
282
 * \return Error code.
283
 *
284
 * \sa \ref igraph_matrix_complex_all_almost_e() and
285
 * \ref igraph_complex_almost_equals() to perform comparisons with relative
286
 * tolerances.
287
 */
288
0
igraph_error_t igraph_matrix_complex_zapsmall(igraph_matrix_complex_t *m, igraph_real_t tol) {
289
0
    return igraph_vector_complex_zapsmall(&m->data, tol);
290
0
}