GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ccolamd.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2005-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26// This is the octave interface to ccolamd, which bore the copyright given
27// in the help of the functions.
28
29#if defined (HAVE_CONFIG_H)
30# include "config.h"
31#endif
32
33#include <cstdlib>
34
35#include "CSparse.h"
36#include "Sparse.h"
37#include "dNDArray.h"
38#include "oct-locbuf.h"
39#include "oct-sparse.h"
40
41#include "defun.h"
42#include "error.h"
43#include "errwarn.h"
44#include "ov.h"
45#include "pager.h"
46
48
49DEFUN (ccolamd, args, nargout,
50 doc: /* -*- texinfo -*-
51@deftypefn {} {@var{p} =} ccolamd (@var{S})
52@deftypefnx {} {@var{p} =} ccolamd (@var{S}, @var{knobs})
53@deftypefnx {} {@var{p} =} ccolamd (@var{S}, @var{knobs}, @var{cmember})
54@deftypefnx {} {[@var{p}, @var{stats}] =} ccolamd (@dots{})
55
56Constrained column approximate minimum degree permutation.
57
58@code{@var{p} = ccolamd (@var{S})} returns the column approximate minimum
59degree permutation vector for the sparse matrix @var{S}. For a
60non-symmetric matrix @var{S}, @code{@var{S}(:, @var{p})} tends to have
61sparser LU@tie{}factors than @var{S}.
62@code{chol (@var{S}(:, @var{p})' * @var{S}(:, @var{p}))} also tends to be
63sparser than @code{chol (@var{S}' * @var{S})}.
64@code{@var{p} = ccolamd (@var{S}, 1)} optimizes the ordering for
65@code{lu (@var{S}(:, @var{p}))}. The ordering is followed by a column
66elimination tree post-ordering.
67
68@var{knobs} is an optional 1-element to 5-element input vector, with a
69default value of @code{[0 10 10 1 0]} if not present or empty. Entries not
70present are set to their defaults.
71
72@table @code
73@item @var{knobs}(1)
74if nonzero, the ordering is optimized for @code{lu (S(:, p))}. It will be a
75poor ordering for @code{chol (@var{S}(:, @var{p})' * @var{S}(:, @var{p}))}.
76This is the most important knob for ccolamd.
77
78@item @var{knobs}(2)
79if @var{S} is m-by-n, rows with more than
80@code{max (16, @var{knobs}(2) * sqrt (n))} entries are ignored.
81
82@item @var{knobs}(3)
83columns with more than
84@code{max (16, @var{knobs}(3) * sqrt (min (@var{m}, @var{n})))} entries are
85ignored and ordered last in the output permutation
86(subject to the cmember constraints).
87
88@item @var{knobs}(4)
89if nonzero, aggressive absorption is performed.
90
91@item @var{knobs}(5)
92if nonzero, statistics and knobs are printed.
93
94@end table
95
96@var{cmember} is an optional vector of length @math{n}. It defines the
97constraints on the column ordering. If @code{@var{cmember}(j) = @var{c}},
98then column @var{j} is in constraint set @var{c} (@var{c} must be in the
99range 1 to n). In the output permutation @var{p}, all columns in set 1
100appear first, followed by all columns in set 2, and so on.
101@code{@var{cmember} = ones (1,n)} if not present or empty.
102@code{ccolamd (@var{S}, [], 1 : n)} returns @code{1 : n}
103
104@code{@var{p} = ccolamd (@var{S})} is about the same as
105@code{@var{p} = colamd (@var{S})}. @var{knobs} and its default values
106differ. @code{colamd} always does aggressive absorption, and it finds an
107ordering suitable for both @code{lu (@var{S}(:, @var{p}))} and @code{chol
108(@var{S}(:, @var{p})' * @var{S}(:, @var{p}))}; it cannot optimize its
109ordering for @code{lu (@var{S}(:, @var{p}))} to the extent that
110@code{ccolamd (@var{S}, 1)} can.
111
112@var{stats} is an optional 20-element output vector that provides data
113about the ordering and the validity of the input matrix @var{S}. Ordering
114statistics are in @code{@var{stats}(1 : 3)}. @code{@var{stats}(1)} and
115@code{@var{stats}(2)} are the number of dense or empty rows and columns
116ignored by @sc{ccolamd} and @code{@var{stats}(3)} is the number of garbage
117collections performed on the internal data structure used by @sc{ccolamd}
118(roughly of size @code{2.2 * nnz (@var{S}) + 4 * @var{m} + 7 * @var{n}}
119integers).
120
121@code{@var{stats}(4 : 7)} provide information if CCOLAMD was able to
122continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if
123invalid. @code{@var{stats}(5)} is the rightmost column index that is
124unsorted or contains duplicate entries, or zero if no such column exists.
125@code{@var{stats}(6)} is the last seen duplicate or out-of-order row
126index in the column index given by @code{@var{stats}(5)}, or zero if no
127such row index exists. @code{@var{stats}(7)} is the number of duplicate
128or out-of-order row indices. @code{@var{stats}(8 : 20)} is always zero in
129the current version of @sc{ccolamd} (reserved for future use).
130
131The authors of the code itself are @nospell{S. Larimore, T. Davis} and
132@nospell{S. Rajamanickam} in collaboration with @nospell{J. Bilbert and E. Ng}.
133Supported by the National Science Foundation
134@nospell{(DMS-9504974, DMS-9803599, CCR-0203270)}, and a grant from
135@nospell{Sandia} National Lab.
136See @url{http://faculty.cse.tamu.edu/davis/suitesparse.html} for ccolamd,
137csymamd, amd, colamd, symamd, and other related orderings.
138@seealso{colamd, csymamd}
139@end deftypefn */)
140{
141#if defined (HAVE_CCOLAMD)
142
143 int nargin = args.length ();
144
145 if (nargin < 1 || nargin > 3)
146 print_usage ();
147
148 octave_value_list retval (nargout == 2 ? 2 : 1);
149 int spumoni = 0;
150
151 // Get knobs
152 static_assert (CCOLAMD_KNOBS <= 40,
153 "ccolamd: # of CCOLAMD_KNOBS exceeded. Please report this to bugs.octave.org");
154 double knob_storage[CCOLAMD_KNOBS];
155 double *knobs = &knob_storage[0];
156 CCOLAMD_NAME (_set_defaults) (knobs);
157
158 // Check for user-passed knobs
159 if (nargin > 1)
160 {
161 NDArray User_knobs = args(1).array_value ();
162 int nel_User_knobs = User_knobs.numel ();
163
164 if (nel_User_knobs > 0)
165 knobs[CCOLAMD_LU] = (User_knobs(0) != 0);
166 if (nel_User_knobs > 1)
167 knobs[CCOLAMD_DENSE_ROW] = User_knobs(1);
168 if (nel_User_knobs > 2)
169 knobs[CCOLAMD_DENSE_COL] = User_knobs(2);
170 if (nel_User_knobs > 3)
171 knobs[CCOLAMD_AGGRESSIVE] = (User_knobs(3) != 0);
172 if (nel_User_knobs > 4)
173 spumoni = (User_knobs(4) != 0);
174
175 // print knob settings if spumoni is set
176 if (spumoni)
177 {
178 octave_stdout << "\nccolamd version " << CCOLAMD_MAIN_VERSION << '.'
179 << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE
180 << ":\nknobs(1): " << User_knobs(0) << ", order for ";
181 if (knobs[CCOLAMD_LU] != 0)
182 octave_stdout << "lu (A)\n";
183 else
184 octave_stdout << "chol (A'*A)\n";
185
186 if (knobs[CCOLAMD_DENSE_ROW] >= 0)
187 octave_stdout << "knobs(2): " << User_knobs(1)
188 << ", rows with > max (16,"
189 << knobs[CCOLAMD_DENSE_ROW]
190 << "* sqrt (columns(A)))"
191 << " entries removed\n";
192 else
193 octave_stdout << "knobs(2): " << User_knobs(1)
194 << ", no dense rows removed\n";
195
196 if (knobs[CCOLAMD_DENSE_COL] >= 0)
197 octave_stdout << "knobs(3): " << User_knobs(2)
198 << ", cols with > max (16,"
199 << knobs[CCOLAMD_DENSE_COL] << "* sqrt (size(A)))"
200 << " entries removed\n";
201 else
202 octave_stdout << "knobs(3): " << User_knobs(2)
203 << ", no dense columns removed\n";
204
205 if (knobs[CCOLAMD_AGGRESSIVE] != 0)
206 octave_stdout << "knobs(4): " << User_knobs(3)
207 << ", aggressive absorption: yes";
208 else
209 octave_stdout << "knobs(4): " << User_knobs(3)
210 << ", aggressive absorption: no";
211
212 octave_stdout << "knobs(5): " << User_knobs(4)
213 << ", statistics and knobs printed\n";
214 }
215 }
216
217 octave_idx_type n_row, n_col, nnz;
218 octave_idx_type *ridx, *cidx;
220 SparseMatrix sm;
221
222 if (args(0).issparse ())
223 {
224 if (args(0).iscomplex ())
225 {
226 scm = args(0).sparse_complex_matrix_value ();
227 n_row = scm.rows ();
228 n_col = scm.cols ();
229 nnz = scm.nnz ();
230 ridx = scm.xridx ();
231 cidx = scm.xcidx ();
232 }
233 else
234 {
235 sm = args(0).sparse_matrix_value ();
236
237 n_row = sm.rows ();
238 n_col = sm.cols ();
239 nnz = sm.nnz ();
240 ridx = sm.xridx ();
241 cidx = sm.xcidx ();
242 }
243 }
244 else
245 {
246 if (args(0).iscomplex ())
247 sm = SparseMatrix (real (args(0).complex_matrix_value ()));
248 else
249 sm = SparseMatrix (args(0).matrix_value ());
250
251 n_row = sm.rows ();
252 n_col = sm.cols ();
253 nnz = sm.nnz ();
254 ridx = sm.xridx ();
255 cidx = sm.xcidx ();
256 }
257
258 // Allocate workspace for ccolamd
260 for (octave_idx_type i = 0; i < n_col+1; i++)
261 p[i] = cidx[i];
262
263 octave_idx_type Alen = CCOLAMD_NAME (_recommended) (nnz, n_row, n_col);
265 for (octave_idx_type i = 0; i < nnz; i++)
266 A[i] = ridx[i];
267
268 static_assert (CCOLAMD_STATS <= 40,
269 "ccolamd: # of CCOLAMD_STATS exceeded. Please report this to bugs.octave.org");
270 suitesparse_integer stats_storage[CCOLAMD_STATS];
271 suitesparse_integer *stats = &stats_storage[0];
272
273 if (nargin > 2)
274 {
275 NDArray in_cmember = args(2).array_value ();
276 octave_idx_type cslen = in_cmember.numel ();
278 for (octave_idx_type i = 0; i < cslen; i++)
279 // convert cmember from 1-based to 0-based
280 cmember[i] = static_cast<suitesparse_integer> (in_cmember(i) - 1);
281
282 if (cslen != n_col)
283 error ("ccolamd: CMEMBER must be of length equal to #cols of A");
284
285 // Order the columns (destroys A)
286 if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, cmember))
287 {
288 CCOLAMD_NAME (_report) (stats);
289
290 error ("ccolamd: internal error!");
291 }
292 }
293 else
294 {
295 // Order the columns (destroys A)
296 if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, nullptr))
297 {
298 CCOLAMD_NAME (_report) (stats);
299
300 error ("ccolamd: internal error!");
301 }
302 }
303
304 // return the permutation vector
305 NDArray out_perm (dim_vector (1, n_col));
306 for (octave_idx_type i = 0; i < n_col; i++)
307 out_perm(i) = p[i] + 1;
308
309 retval(0) = out_perm;
310
311 // print stats if spumoni > 0
312 if (spumoni > 0)
313 CCOLAMD_NAME (_report) (stats);
314
315 // Return the stats vector
316 if (nargout == 2)
317 {
318 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
319 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
320 out_stats(i) = stats[i];
321 retval(1) = out_stats;
322
323 // fix stats (5) and (6), for 1-based information on
324 // jumbled matrix. note that this correction doesn't
325 // occur if symamd returns FALSE
326 out_stats(CCOLAMD_INFO1)++;
327 out_stats(CCOLAMD_INFO2)++;
328 }
329
330 return retval;
331
332#else
333
334 octave_unused_parameter (args);
335 octave_unused_parameter (nargout);
336
337 err_disabled_feature ("ccolamd", "CCOLAMD");
338
339#endif
340}
341
342DEFUN (csymamd, args, nargout,
343 doc: /* -*- texinfo -*-
344@deftypefn {} {@var{p} =} csymamd (@var{S})
345@deftypefnx {} {@var{p} =} csymamd (@var{S}, @var{knobs})
346@deftypefnx {} {@var{p} =} csymamd (@var{S}, @var{knobs}, @var{cmember})
347@deftypefnx {} {[@var{p}, @var{stats}] =} csymamd (@dots{})
348
349For a symmetric positive definite matrix @var{S}, return the permutation
350vector @var{p} such that @code{@var{S}(@var{p},@var{p})} tends to have a
351sparser Cholesky@tie{}factor than @var{S}.
352
353Sometimes @code{csymamd} works well for symmetric indefinite matrices too.
354The matrix @var{S} is assumed to be symmetric; only the strictly lower
355triangular part is referenced. @var{S} must be square. The ordering is
356followed by an elimination tree post-ordering.
357
358@var{knobs} is an optional 1-element to 3-element input vector, with a
359default value of @code{[10 1 0]}. Entries not present are set to their
360defaults.
361
362@table @code
363@item @var{knobs}(1)
364If @var{S} is n-by-n, then rows and columns with more than
365@code{max(16,@var{knobs}(1)*sqrt(n))} entries are ignored, and ordered
366last in the output permutation (subject to the cmember constraints).
367
368@item @var{knobs}(2)
369If nonzero, aggressive absorption is performed.
370
371@item @var{knobs}(3)
372If nonzero, statistics and knobs are printed.
373
374@end table
375
376@var{cmember} is an optional vector of length n. It defines the constraints
377on the ordering. If @code{@var{cmember}(j) = @var{S}}, then row/column j is
378in constraint set @var{c} (@var{c} must be in the range 1 to n). In the
379output permutation @var{p}, rows/columns in set 1 appear first, followed
380by all rows/columns in set 2, and so on. @code{@var{cmember} = ones (1,n)}
381if not present or empty. @code{csymamd (@var{S},[],1:n)} returns
382@code{1:n}.
383
384@code{@var{p} = csymamd (@var{S})} is about the same as
385@code{@var{p} = symamd (@var{S})}. @var{knobs} and its default values
386differ.
387
388@code{@var{stats}(4:7)} provide information if CCOLAMD was able to
389continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if
390invalid. @code{@var{stats}(5)} is the rightmost column index that is
391unsorted or contains duplicate entries, or zero if no such column exists.
392@code{@var{stats}(6)} is the last seen duplicate or out-of-order row
393index in the column index given by @code{@var{stats}(5)}, or zero if no
394such row index exists. @code{@var{stats}(7)} is the number of duplicate
395or out-of-order row indices. @code{@var{stats}(8:20)} is always zero in
396the current version of @sc{ccolamd} (reserved for future use).
397
398The authors of the code itself are @nospell{S. Larimore, T. Davis} and
399@nospell{S. Rajamanickam} in collaboration with @nospell{J. Bilbert and E. Ng}.
400Supported by the National Science Foundation
401@nospell{(DMS-9504974, DMS-9803599, CCR-0203270)}, and a grant from
402@nospell{Sandia} National Lab.
403See @url{http://faculty.cse.tamu.edu/davis/suitesparse.html} for ccolamd,
404colamd, csymamd, amd, colamd, symamd, and other related orderings.
405@seealso{symamd, ccolamd}
406@end deftypefn */)
407{
408#if defined (HAVE_CCOLAMD)
409
410 int nargin = args.length ();
411
412 if (nargin < 1 || nargin > 3)
413 print_usage ();
414
415 octave_value_list retval (nargout == 2 ? 2 : 1);
416 int spumoni = 0;
417
418 // Get knobs
419 static_assert (CCOLAMD_KNOBS <= 40,
420 "csymamd: # of CCOLAMD_KNOBS exceeded. Please report this to bugs.octave.org");
421 double knob_storage[CCOLAMD_KNOBS];
422 double *knobs = &knob_storage[0];
423 CCOLAMD_NAME (_set_defaults) (knobs);
424
425 // Check for user-passed knobs
426 if (nargin > 1)
427 {
428 NDArray User_knobs = args(1).array_value ();
429 int nel_User_knobs = User_knobs.numel ();
430
431 if (nel_User_knobs > 0)
432 knobs[CCOLAMD_DENSE_ROW] = User_knobs(0);
433 if (nel_User_knobs > 1)
434 knobs[CCOLAMD_AGGRESSIVE] = User_knobs(1);
435 if (nel_User_knobs > 2)
436 spumoni = static_cast<int> (User_knobs(2));
437
438 // print knob settings if spumoni is set
439 if (spumoni)
440 {
441 octave_stdout << "\ncsymamd version " << CCOLAMD_MAIN_VERSION
442 << '.' << CCOLAMD_SUB_VERSION
443 << ", " << CCOLAMD_DATE << "\n";
444
445 if (knobs[CCOLAMD_DENSE_ROW] >= 0)
446 octave_stdout << "knobs(1): " << User_knobs(0)
447 << ", rows/cols with > max (16,"
448 << knobs[CCOLAMD_DENSE_ROW]
449 << "* sqrt (columns(A)))"
450 << " entries removed\n";
451 else
452 octave_stdout << "knobs(1): " << User_knobs(0)
453 << ", no dense rows/cols removed\n";
454
455 if (knobs[CCOLAMD_AGGRESSIVE] != 0)
456 octave_stdout << "knobs(2): " << User_knobs(1)
457 << ", aggressive absorption: yes";
458 else
459 octave_stdout << "knobs(2): " << User_knobs(1)
460 << ", aggressive absorption: no";
461
462 octave_stdout << "knobs(3): " << User_knobs(2)
463 << ", statistics and knobs printed\n";
464 }
465 }
466
467 octave_idx_type n_row, n_col;
468 octave_idx_type *ridx, *cidx;
469 SparseMatrix sm;
471
472 if (args(0).issparse ())
473 {
474 if (args(0).iscomplex ())
475 {
476 scm = args(0).sparse_complex_matrix_value ();
477 n_row = scm.rows ();
478 n_col = scm.cols ();
479 ridx = scm.xridx ();
480 cidx = scm.xcidx ();
481 }
482 else
483 {
484 sm = args(0).sparse_matrix_value ();
485 n_row = sm.rows ();
486 n_col = sm.cols ();
487 ridx = sm.xridx ();
488 cidx = sm.xcidx ();
489 }
490 }
491 else
492 {
493 if (args(0).iscomplex ())
494 sm = SparseMatrix (real (args(0).complex_matrix_value ()));
495 else
496 sm = SparseMatrix (args(0).matrix_value ());
497
498 n_row = sm.rows ();
499 n_col = sm.cols ();
500 ridx = sm.xridx ();
501 cidx = sm.xcidx ();
502 }
503
504 if (n_row != n_col)
505 err_square_matrix_required ("csymamd", "S");
506
507 // Allocate workspace for symamd
509 static_assert (CCOLAMD_STATS <= 40,
510 "csymamd: # of CCOLAMD_STATS exceeded. Please report this to bugs.octave.org");
511 suitesparse_integer stats_storage[CCOLAMD_STATS];
512 suitesparse_integer *stats = &stats_storage[0];
513
514 if (nargin > 2)
515 {
516 NDArray in_cmember = args(2).array_value ();
517 octave_idx_type cslen = in_cmember.numel ();
519 for (octave_idx_type i = 0; i < cslen; i++)
520 // convert cmember from 1-based to 0-based
521 cmember[i] = static_cast<octave_idx_type> (in_cmember(i) - 1);
522
523 if (cslen != n_col)
524 error ("csymamd: CMEMBER must be of length equal to #cols of A");
525
526 if (! CSYMAMD_NAME () (n_col,
529 perm, knobs, stats, &calloc, &free, cmember, -1))
530 {
531 CSYMAMD_NAME (_report)(stats);
532
533 error ("csymamd: internal error!");
534 }
535 }
536 else
537 {
538 if (! CSYMAMD_NAME () (n_col,
541 perm, knobs, stats, &calloc, &free, nullptr, -1))
542 {
543 CSYMAMD_NAME (_report)(stats);
544
545 error ("csymamd: internal error!");
546 }
547 }
548
549 // return the permutation vector
550 NDArray out_perm (dim_vector (1, n_col));
551 for (octave_idx_type i = 0; i < n_col; i++)
552 out_perm(i) = perm[i] + 1;
553
554 retval(0) = out_perm;
555
556 // print stats if spumoni > 0
557 if (spumoni > 0)
558 CSYMAMD_NAME (_report)(stats);
559
560 // Return the stats vector
561 if (nargout == 2)
562 {
563 NDArray out_stats (dim_vector (1, CCOLAMD_STATS));
564 for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++)
565 out_stats(i) = stats[i];
566 retval(1) = out_stats;
567
568 // fix stats (5) and (6), for 1-based information on
569 // jumbled matrix. note that this correction doesn't
570 // occur if symamd returns FALSE
571 out_stats(CCOLAMD_INFO1)++;
572 out_stats(CCOLAMD_INFO2)++;
573 }
574
575 return retval;
576
577#else
578
579 octave_unused_parameter (args);
580 octave_unused_parameter (nargout);
581
582 err_disabled_feature ("csymamd", "CCOLAMD");
583
584#endif
585}
586
587OCTAVE_END_NAMESPACE(octave)
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
octave_idx_type cols() const
Definition Sparse.h:349
octave_idx_type nnz() const
Actual number of nonzero terms.
Definition Sparse.h:336
octave_idx_type rows() const
Definition Sparse.h:348
octave_idx_type * xcidx()
Definition Sparse.h:599
octave_idx_type * xridx()
Definition Sparse.h:586
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
ColumnVector real(const ComplexColumnVector &a)
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition defun.h:56
void error(const char *fmt,...)
Definition error.cc:1003
void err_square_matrix_required(const char *fcn, const char *name)
Definition errwarn.cc:122
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition errwarn.cc:53
F77_RET_T const F77_INT F77_CMPLX * A
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
suitesparse_integer * to_suitesparse_intptr(octave_idx_type *i)
Definition oct-sparse.cc:51
#define CCOLAMD_NAME(name)
Definition oct-sparse.h:131
int suitesparse_integer
Definition oct-sparse.h:184
#define CSYMAMD_NAME(name)
Definition oct-sparse.h:132
void free(void *)
#define octave_stdout
Definition pager.h:301