GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
tril.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2004-2021 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 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <algorithm>
31 #include "Array.h"
32 #include "Sparse.h"
33 #include "mx-base.h"
34 
35 #include "ov.h"
36 #include "Cell.h"
37 
38 #include "defun.h"
39 #include "error.h"
40 #include "ovl.h"
41 
42 // The bulk of the work.
43 template <typename T>
44 static Array<T>
45 do_tril (const Array<T>& a, octave_idx_type k, bool pack)
46 {
47  octave_idx_type nr = a.rows ();
48  octave_idx_type nc = a.columns ();
49  const T *avec = a.fortran_vec ();
50  octave_idx_type zero = 0;
51 
52  if (pack)
53  {
54  octave_idx_type j1 = std::min (std::max (zero, k), nc);
55  octave_idx_type j2 = std::min (std::max (zero, nr + k), nc);
56  octave_idx_type n = j1 * nr + ((j2 - j1) * (nr-(j1-k) + nr-(j2-1-k))) / 2;
57  Array<T> r (dim_vector (n, 1));
58  T *rvec = r.fortran_vec ();
59  for (octave_idx_type j = 0; j < nc; j++)
60  {
61  octave_idx_type ii = std::min (std::max (zero, j - k), nr);
62  rvec = std::copy (avec + ii, avec + nr, rvec);
63  avec += nr;
64  }
65 
66  return r;
67  }
68  else
69  {
70  Array<T> r (a.dims ());
71  T *rvec = r.fortran_vec ();
72  for (octave_idx_type j = 0; j < nc; j++)
73  {
74  octave_idx_type ii = std::min (std::max (zero, j - k), nr);
75  std::fill (rvec, rvec + ii, T ());
76  std::copy (avec + ii, avec + nr, rvec + ii);
77  avec += nr;
78  rvec += nr;
79  }
80 
81  return r;
82  }
83 }
84 
85 template <typename T>
86 static Array<T>
87 do_triu (const Array<T>& a, octave_idx_type k, bool pack)
88 {
89  octave_idx_type nr = a.rows ();
90  octave_idx_type nc = a.columns ();
91  const T *avec = a.fortran_vec ();
92  octave_idx_type zero = 0;
93 
94  if (pack)
95  {
96  octave_idx_type j1 = std::min (std::max (zero, k), nc);
97  octave_idx_type j2 = std::min (std::max (zero, nr + k), nc);
99  = ((j2 - j1) * ((j1+1-k) + (j2-k))) / 2 + (nc - j2) * nr;
100  Array<T> r (dim_vector (n, 1));
101  T *rvec = r.fortran_vec ();
102  for (octave_idx_type j = 0; j < nc; j++)
103  {
104  octave_idx_type ii = std::min (std::max (zero, j + 1 - k), nr);
105  rvec = std::copy (avec, avec + ii, rvec);
106  avec += nr;
107  }
108 
109  return r;
110  }
111  else
112  {
113  Array<T> r (a.dims ());
114  T *rvec = r.fortran_vec ();
115  for (octave_idx_type j = 0; j < nc; j++)
116  {
117  octave_idx_type ii = std::min (std::max (zero, j + 1 - k), nr);
118  std::copy (avec, avec + ii, rvec);
119  std::fill (rvec + ii, rvec + nr, T ());
120  avec += nr;
121  rvec += nr;
122  }
123 
124  return r;
125  }
126 }
127 
128 // These two are by David Bateman.
129 // FIXME: optimizations possible. "pack" support missing.
130 
131 template <typename T>
132 static Sparse<T>
133 do_tril (const Sparse<T>& a, octave_idx_type k, bool pack)
134 {
135  if (pack) // FIXME
136  error (R"(tril: "pack" not implemented for sparse matrices)");
137 
138  Sparse<T> m = a;
139  octave_idx_type nc = m.cols ();
140 
141  for (octave_idx_type j = 0; j < nc; j++)
142  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
143  if (m.ridx (i) < j-k)
144  m.data(i) = 0.;
145 
146  m.maybe_compress (true);
147 
148  return m;
149 }
150 
151 template <typename T>
152 static Sparse<T>
153 do_triu (const Sparse<T>& a, octave_idx_type k, bool pack)
154 {
155  if (pack) // FIXME
156  error (R"(triu: "pack" not implemented for sparse matrices)");
157 
158  Sparse<T> m = a;
159  octave_idx_type nc = m.cols ();
160 
161  for (octave_idx_type j = 0; j < nc; j++)
162  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
163  if (m.ridx (i) > j-k)
164  m.data(i) = 0.;
165 
166  m.maybe_compress (true);
167  return m;
168 }
169 
170 // Convenience dispatchers.
171 template <typename T>
172 static Array<T>
173 do_trilu (const Array<T>& a, octave_idx_type k, bool lower, bool pack)
174 {
175  return lower ? do_tril (a, k, pack) : do_triu (a, k, pack);
176 }
177 
178 template <typename T>
179 static Sparse<T>
180 do_trilu (const Sparse<T>& a, octave_idx_type k, bool lower, bool pack)
181 {
182  return lower ? do_tril (a, k, pack) : do_triu (a, k, pack);
183 }
184 
185 static octave_value
186 do_trilu (const std::string& name,
187  const octave_value_list& args)
188 {
189  bool lower = (name == "tril");
190 
191  int nargin = args.length ();
192  bool pack = false;
193 
194  if (nargin >= 2 && args(nargin-1).is_string ())
195  {
196  pack = (args(nargin-1).string_value () == "pack");
197  nargin--;
198  }
199 
200  if (nargin < 1 || nargin > 2)
201  print_usage ();
202 
203  octave_idx_type k = 0;
204  if (nargin == 2)
205  k = args(1).idx_type_value (true);
206 
207  octave_value arg = args(0);
208 
209  dim_vector dims = arg.dims ();
210  if (dims.ndims () != 2)
211  error ("%s: need a 2-D matrix", name.c_str ());
212  else if (k < -dims(0) || k > dims(1))
213  error ("%s: requested diagonal out of range", name.c_str ());
214 
216 
217  switch (arg.builtin_type ())
218  {
219  case btyp_double:
220  if (arg.issparse ())
221  retval = do_trilu (arg.sparse_matrix_value (), k, lower, pack);
222  else
223  retval = do_trilu (arg.array_value (), k, lower, pack);
224  break;
225 
226  case btyp_complex:
227  if (arg.issparse ())
228  retval = do_trilu (arg.sparse_complex_matrix_value (), k, lower,
229  pack);
230  else
231  retval = do_trilu (arg.complex_array_value (), k, lower, pack);
232  break;
233 
234  case btyp_bool:
235  if (arg.issparse ())
236  retval = do_trilu (arg.sparse_bool_matrix_value (), k, lower,
237  pack);
238  else
239  retval = do_trilu (arg.bool_array_value (), k, lower, pack);
240  break;
241 
242 #define ARRAYCASE(TYP) \
243  case btyp_ ## TYP: \
244  retval = do_trilu (arg.TYP ## _array_value (), k, lower, pack); \
245  break
246 
247  ARRAYCASE (float);
248  ARRAYCASE (float_complex);
249  ARRAYCASE (int8);
250  ARRAYCASE (int16);
251  ARRAYCASE (int32);
252  ARRAYCASE (int64);
253  ARRAYCASE (uint8);
254  ARRAYCASE (uint16);
255  ARRAYCASE (uint32);
256  ARRAYCASE (uint64);
257  ARRAYCASE (char);
258 
259 #undef ARRAYCASE
260 
261  default:
262  {
263  // Generic code that works on octave-values, that is slow
264  // but will also work on arbitrary user types
265  if (pack) // FIXME
266  error (R"(%s: "pack" not implemented for class %s)",
267  name.c_str (), arg.class_name ().c_str ());
268 
269  octave_value tmp = arg;
270  if (arg.isempty ())
271  return arg;
272 
273  octave_idx_type nr = dims(0);
274  octave_idx_type nc = dims(1);
275 
276  // The sole purpose of this code is to force the correct matrix size.
277  // This would not be necessary if the octave_value resize function
278  // allowed a fill_value. It also allows odd attributes in some user
279  // types to be handled. With a fill_value, it should be replaced with
280  //
281  // octave_value_list ov_idx;
282  // tmp = tmp.resize(dim_vector (0,0)).resize (dims, fill_value);
283 
284  octave_value_list ov_idx;
285  std::list<octave_value_list> idx_tmp;
286  ov_idx(1) = static_cast<double> (nc+1);
287  ov_idx(0) = Range (1, nr);
288  idx_tmp.push_back (ov_idx);
289  ov_idx(1) = static_cast<double> (nc);
290  tmp = tmp.resize (dim_vector (0,0));
291  tmp = tmp.subsasgn ("(", idx_tmp, arg.do_index_op (ov_idx));
292  tmp = tmp.resize (dims);
293 
294  if (lower)
295  {
296  octave_idx_type st = (nc < nr + k ? nc : nr + k);
297 
298  for (octave_idx_type j = 1; j <= st; j++)
299  {
300  octave_idx_type nr_limit = (1 > j - k ? 1 : j - k);
301  ov_idx(1) = static_cast<double> (j);
302  ov_idx(0) = Range (nr_limit, nr);
303  std::list<octave_value_list> idx;
304  idx.push_back (ov_idx);
305 
306  tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
307  }
308  }
309  else
310  {
311  octave_idx_type st = (k + 1 > 1 ? k + 1 : 1);
312 
313  for (octave_idx_type j = st; j <= nc; j++)
314  {
315  octave_idx_type nr_limit = (nr < j - k ? nr : j - k);
316  ov_idx(1) = static_cast<double> (j);
317  ov_idx(0) = Range (1, nr_limit);
318  std::list<octave_value_list> idx;
319  idx.push_back (ov_idx);
320 
321  tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
322  }
323  }
324 
325  retval = tmp;
326  }
327  }
328 
329  return retval;
330 }
331 
332 DEFUN (tril, args, ,
333  doc: /* -*- texinfo -*-
334 @deftypefn {} {@var{A_LO} =} tril (@var{A})
335 @deftypefnx {} {@var{A_LO} =} tril (@var{A}, @var{k})
336 @deftypefnx {} {@var{A_LO} =} tril (@var{A}, @var{k}, @var{pack})
337 Return a new matrix formed by extracting the lower triangular part of the
338 matrix @var{A}, and setting all other elements to zero.
339 
340 The optional second argument specifies how many diagonals above or below the
341 main diagonal should also be set to zero. The default value of @var{k} is
342 zero which includes the main diagonal as part of the result. If the value of
343 @var{k} is a nonzero integer then the selection of elements starts at an offset
344 of @var{k} diagonals above the main diagonal for positive @var{k} or below the
345 main diagonal for negative @var{k}. The absolute value of @var{k} may not be
346 greater than the number of subdiagonals or superdiagonals.
347 
348 Example 1 : exclude main diagonal
349 
350 @example
351 @group
352 tril (ones (3), -1)
353  @result{} 0 0 0
354  1 0 0
355  1 1 0
356 @end group
357 @end example
358 
359 @noindent
360 
361 Example 2 : include first superdiagonal
362 
363 @example
364 @group
365 tril (ones (3), 1)
366  @result{} 1 1 0
367  1 1 1
368  1 1 1
369 @end group
370 @end example
371 
372 If the optional third argument @qcode{"pack"} is given then the extracted
373 elements are not inserted into a matrix, but instead stacked column-wise one
374 above another, and returned as a column vector.
375 @seealso{triu, istril, diag}
376 @end deftypefn */)
377 {
378  return do_trilu ("tril", args);
379 }
380 
381 DEFUN (triu, args, ,
382  doc: /* -*- texinfo -*-
383 @deftypefn {} {@var{A_UP} =} triu (@var{A})
384 @deftypefnx {} {@var{A_UP} =} triu (@var{A}, @var{k})
385 @deftypefnx {} {@var{A_UP} =} triu (@var{A}, @var{k}, @var{pack})
386 Return a new matrix formed by extracting the upper triangular part of the
387 matrix @var{A}, and setting all other elements to zero.
388 
389 The optional second argument specifies how many diagonals above or below the
390 main diagonal should also be set to zero. The default value of @var{k} is
391 zero which includes the main diagonal as part of the result. If the value of
392 @var{k} is a nonzero integer then the selection of elements starts at an offset
393 of @var{k} diagonals above the main diagonal for positive @var{k} or below the
394 main diagonal for negative @var{k}. The absolute value of @var{k} may not be
395 greater than the number of subdiagonals or superdiagonals.
396 
397 Example 1 : exclude main diagonal
398 
399 @example
400 @group
401 triu (ones (3), 1)
402  @result{} 0 1 1
403  0 0 1
404  0 0 0
405 @end group
406 @end example
407 
408 @noindent
409 
410 Example 2 : include first subdiagonal
411 
412 @example
413 @group
414 triu (ones (3), -1)
415  @result{} 1 1 1
416  1 1 1
417  0 1 1
418 @end group
419 @end example
420 
421 If the optional third argument @qcode{"pack"} is given then the extracted
422 elements are not inserted into a matrix, but instead stacked column-wise one
423 above another, and returned as a column vector.
424 @seealso{tril, istriu, diag}
425 @end deftypefn */)
426 {
427  return do_trilu ("triu", args);
428 }
429 
430 /*
431 %!test
432 %! a = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
433 %!
434 %! l0 = [1, 0, 0; 4, 5, 0; 7, 8, 9; 10, 11, 12];
435 %! l1 = [1, 2, 0; 4, 5, 6; 7, 8, 9; 10, 11, 12];
436 %! l2 = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
437 %! lm1 = [0, 0, 0; 4, 0, 0; 7, 8, 0; 10, 11, 12];
438 %! lm2 = [0, 0, 0; 0, 0, 0; 7, 0, 0; 10, 11, 0];
439 %! lm3 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 10, 0, 0];
440 %! lm4 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 0, 0, 0];
441 %!
442 %! assert (tril (a, -4), lm4);
443 %! assert (tril (a, -3), lm3);
444 %! assert (tril (a, -2), lm2);
445 %! assert (tril (a, -1), lm1);
446 %! assert (tril (a), l0);
447 %! assert (tril (a, 1), l1);
448 %! assert (tril (a, 2), l2);
449 
450 %!error tril ()
451 */
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:128
octave_idx_type columns(void) const
Definition: Array.h:424
octave_idx_type rows(void) const
Definition: Array.h:415
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
Definition: Range.h:40
Definition: Sparse.h:49
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:334
octave_idx_type length(void) const
Definition: ovl.h:113
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:844
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:853
bool issparse(void) const
Definition: ov.h:706
builtin_type_t builtin_type(void) const
Definition: ov.h:643
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:475
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:831
std::string class_name(void) const
Definition: ov.h:1256
bool isempty(void) const
Definition: ov.h:557
SparseBoolMatrix sparse_bool_matrix_value(bool warn=false) const
Definition: ov.h:860
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:812
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:539
dim_vector dims(void) const
Definition: ov.h:500
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:857
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#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:968
QString name
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
@ btyp_double
Definition: ov-base.h:73
@ btyp_bool
Definition: ov-base.h:85
@ btyp_complex
Definition: ov-base.h:75
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
static Array< T > do_triu(const Array< T > &a, octave_idx_type k, bool pack)
Definition: tril.cc:87
#define ARRAYCASE(TYP)
static Array< T > do_trilu(const Array< T > &a, octave_idx_type k, bool lower, bool pack)
Definition: tril.cc:173
static Array< T > do_tril(const Array< T > &a, octave_idx_type k, bool pack)
Definition: tril.cc:45