GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
tril.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2004-2015 David Bateman
4 Copyright (C) 2009 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <algorithm>
29 #include "Array.h"
30 #include "Sparse.h"
31 #include "mx-base.h"
32 
33 #include "ov.h"
34 #include "Cell.h"
35 
36 #include "defun.h"
37 #include "error.h"
38 #include "oct-obj.h"
39 
40 // The bulk of the work.
41 template <class T>
42 static Array<T>
43 do_tril (const Array<T>& a, octave_idx_type k, bool pack)
44 {
45  octave_idx_type nr = a.rows ();
46  octave_idx_type nc = a.columns ();
47  const T *avec = a.fortran_vec ();
48  octave_idx_type zero = 0;
49 
50  if (pack)
51  {
52  octave_idx_type j1 = std::min (std::max (zero, k), nc);
53  octave_idx_type j2 = std::min (std::max (zero, nr + k), nc);
54  octave_idx_type n = j1 * nr + ((j2 - j1) * (nr-(j1-k) + nr-(j2-1-k))) / 2;
55  Array<T> r (dim_vector (n, 1));
56  T *rvec = r.fortran_vec ();
57  for (octave_idx_type j = 0; j < nc; j++)
58  {
59  octave_idx_type ii = std::min (std::max (zero, j - k), nr);
60  rvec = std::copy (avec + ii, avec + nr, rvec);
61  avec += nr;
62  }
63 
64  return r;
65  }
66  else
67  {
68  Array<T> r (a.dims ());
69  T *rvec = r.fortran_vec ();
70  for (octave_idx_type j = 0; j < nc; j++)
71  {
72  octave_idx_type ii = std::min (std::max (zero, j - k), nr);
73  std::fill (rvec, rvec + ii, T ());
74  std::copy (avec + ii, avec + nr, rvec + ii);
75  avec += nr;
76  rvec += nr;
77  }
78 
79  return r;
80  }
81 }
82 
83 template <class T>
84 static Array<T>
85 do_triu (const Array<T>& a, octave_idx_type k, bool pack)
86 {
87  octave_idx_type nr = a.rows ();
88  octave_idx_type nc = a.columns ();
89  const T *avec = a.fortran_vec ();
90  octave_idx_type zero = 0;
91 
92  if (pack)
93  {
94  octave_idx_type j1 = std::min (std::max (zero, k), nc);
95  octave_idx_type j2 = std::min (std::max (zero, nr + k), nc);
97  = ((j2 - j1) * ((j1+1-k) + (j2-k))) / 2 + (nc - j2) * nr;
98  Array<T> r (dim_vector (n, 1));
99  T *rvec = r.fortran_vec ();
100  for (octave_idx_type j = 0; j < nc; j++)
101  {
102  octave_idx_type ii = std::min (std::max (zero, j + 1 - k), nr);
103  rvec = std::copy (avec, avec + ii, rvec);
104  avec += nr;
105  }
106 
107  return r;
108  }
109  else
110  {
111  NoAlias<Array<T> > r (a.dims ());
112  T *rvec = r.fortran_vec ();
113  for (octave_idx_type j = 0; j < nc; j++)
114  {
115  octave_idx_type ii = std::min (std::max (zero, j + 1 - k), nr);
116  std::copy (avec, avec + ii, rvec);
117  std::fill (rvec + ii, rvec + nr, T ());
118  avec += nr;
119  rvec += nr;
120  }
121 
122  return r;
123  }
124 }
125 
126 // These two are by David Bateman.
127 // FIXME: optimizations possible. "pack" support missing.
128 
129 template <class T>
130 static Sparse<T>
131 do_tril (const Sparse<T>& a, octave_idx_type k, bool pack)
132 {
133  if (pack) // FIXME
134  {
135  error ("tril: \"pack\" not implemented for sparse matrices");
136  return Sparse<T> ();
137  }
138 
139  Sparse<T> m = a;
140  octave_idx_type nc = m.cols ();
141 
142  for (octave_idx_type j = 0; j < nc; j++)
143  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
144  if (m.ridx (i) < j-k)
145  m.data(i) = 0.;
146 
147  m.maybe_compress (true);
148  return m;
149 }
150 
151 template <class T>
152 static Sparse<T>
153 do_triu (const Sparse<T>& a, octave_idx_type k, bool pack)
154 {
155  if (pack) // FIXME
156  {
157  error ("triu: \"pack\" not implemented for sparse matrices");
158  return Sparse<T> ();
159  }
160 
161  Sparse<T> m = a;
162  octave_idx_type nc = m.cols ();
163 
164  for (octave_idx_type j = 0; j < nc; j++)
165  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
166  if (m.ridx (i) > j-k)
167  m.data(i) = 0.;
168 
169  m.maybe_compress (true);
170  return m;
171 }
172 
173 // Convenience dispatchers.
174 template <class T>
175 static Array<T>
176 do_trilu (const Array<T>& a, octave_idx_type k, bool lower, bool pack)
177 {
178  return lower ? do_tril (a, k, pack) : do_triu (a, k, pack);
179 }
180 
181 template <class T>
182 static Sparse<T>
183 do_trilu (const Sparse<T>& a, octave_idx_type k, bool lower, bool pack)
184 {
185  return lower ? do_tril (a, k, pack) : do_triu (a, k, pack);
186 }
187 
188 static octave_value
189 do_trilu (const std::string& name,
190  const octave_value_list& args)
191 {
192  bool lower = name == "tril";
193 
194  octave_value retval;
195  int nargin = args.length ();
196  octave_idx_type k = 0;
197  bool pack = false;
198  if (nargin >= 2 && args(nargin-1).is_string ())
199  {
200  pack = args(nargin-1).string_value () == "pack";
201  nargin--;
202  }
203 
204  if (nargin == 2)
205  {
206  k = args(1).int_value (true);
207 
208  if (error_state)
209  return retval;
210  }
211 
212  if (nargin < 1 || nargin > 2)
213  print_usage ();
214  else
215  {
216  octave_value arg = args(0);
217 
218  dim_vector dims = arg.dims ();
219  if (dims.length () != 2)
220  error ("%s: need a 2-D matrix", name.c_str ());
221  else if (k < -dims (0) || k > dims(1))
222  error ("%s: requested diagonal out of range", name.c_str ());
223  else
224  {
225  switch (arg.builtin_type ())
226  {
227  case btyp_double:
228  if (arg.is_sparse_type ())
229  retval = do_trilu (arg.sparse_matrix_value (), k, lower, pack);
230  else
231  retval = do_trilu (arg.array_value (), k, lower, pack);
232  break;
233  case btyp_complex:
234  if (arg.is_sparse_type ())
235  retval = do_trilu (arg.sparse_complex_matrix_value (), k, lower,
236  pack);
237  else
238  retval = do_trilu (arg.complex_array_value (), k, lower, pack);
239  break;
240  case btyp_bool:
241  if (arg.is_sparse_type ())
242  retval = do_trilu (arg.sparse_bool_matrix_value (), k, lower,
243  pack);
244  else
245  retval = do_trilu (arg.bool_array_value (), k, lower, pack);
246  break;
247 #define ARRAYCASE(TYP) \
248  case btyp_ ## TYP: \
249  retval = do_trilu (arg.TYP ## _array_value (), k, lower, pack); \
250  break
251  ARRAYCASE (float);
252  ARRAYCASE (float_complex);
253  ARRAYCASE (int8);
254  ARRAYCASE (int16);
255  ARRAYCASE (int32);
256  ARRAYCASE (int64);
257  ARRAYCASE (uint8);
258  ARRAYCASE (uint16);
259  ARRAYCASE (uint32);
260  ARRAYCASE (uint64);
261  ARRAYCASE (char);
262 #undef ARRAYCASE
263  default:
264  {
265  // Generic code that works on octave-values, that is slow
266  // but will also work on arbitrary user types
267 
268  if (pack) // FIXME
269  {
270  error ("%s: \"pack\" not implemented for class %s",
271  name.c_str (), arg.class_name ().c_str ());
272  return octave_value ();
273  }
274 
275  octave_value tmp = arg;
276  if (arg.numel () == 0)
277  return arg;
278 
279  octave_idx_type nr = dims(0);
280  octave_idx_type nc = dims(1);
281 
282  // The sole purpose of the below is to force the correct
283  // matrix size. This would not be necessary if the
284  // octave_value resize function allowed a fill_value.
285  // It also allows odd attributes in some user types
286  // to be handled. With a fill_value ot should be replaced
287  // with
288  //
289  // octave_value_list ov_idx;
290  // tmp = tmp.resize(dim_vector (0,0)).resize (dims, fill_value);
291 
292  octave_value_list ov_idx;
293  std::list<octave_value_list> idx_tmp;
294  ov_idx(1) = static_cast<double> (nc+1);
295  ov_idx(0) = Range (1, nr);
296  idx_tmp.push_back (ov_idx);
297  ov_idx(1) = static_cast<double> (nc);
298  tmp = tmp.resize (dim_vector (0,0));
299  tmp = tmp.subsasgn ("(",idx_tmp, arg.do_index_op (ov_idx));
300  tmp = tmp.resize (dims);
301 
302  if (lower)
303  {
304  octave_idx_type st = nc < nr + k ? nc : nr + k;
305 
306  for (octave_idx_type j = 1; j <= st; j++)
307  {
308  octave_idx_type nr_limit = 1 > j - k ? 1 : j - k;
309  ov_idx(1) = static_cast<double> (j);
310  ov_idx(0) = Range (nr_limit, nr);
311  std::list<octave_value_list> idx;
312  idx.push_back (ov_idx);
313 
314  tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
315 
316  if (error_state)
317  return retval;
318  }
319  }
320  else
321  {
322  octave_idx_type st = k + 1 > 1 ? k + 1 : 1;
323 
324  for (octave_idx_type j = st; j <= nc; j++)
325  {
326  octave_idx_type nr_limit = nr < j - k ? nr : j - k;
327  ov_idx(1) = static_cast<double> (j);
328  ov_idx(0) = Range (1, nr_limit);
329  std::list<octave_value_list> idx;
330  idx.push_back (ov_idx);
331 
332  tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
333 
334  if (error_state)
335  return retval;
336  }
337  }
338 
339  retval = tmp;
340  }
341  }
342  }
343  }
344 
345  return retval;
346 }
347 
348 DEFUN (tril, args, ,
349  "-*- texinfo -*-\n\
350 @deftypefn {Function File} {} tril (@var{A})\n\
351 @deftypefnx {Function File} {} tril (@var{A}, @var{k})\n\
352 @deftypefnx {Function File} {} tril (@var{A}, @var{k}, @var{pack})\n\
353 @deftypefnx {Function File} {} triu (@var{A})\n\
354 @deftypefnx {Function File} {} triu (@var{A}, @var{k})\n\
355 @deftypefnx {Function File} {} triu (@var{A}, @var{k}, @var{pack})\n\
356 Return a new matrix formed by extracting the lower (@code{tril})\n\
357 or upper (@code{triu}) triangular part of the matrix @var{A}, and\n\
358 setting all other elements to zero.\n\
359 \n\
360 The second argument is optional, and specifies how many diagonals above or\n\
361 below the main diagonal should also be set to zero.\n\
362 \n\
363 The default value of @var{k} is zero, so that @code{triu} and @code{tril}\n\
364 normally include the main diagonal as part of the result.\n\
365 \n\
366 If the value of @var{k} is nonzero integer, the selection of elements starts\n\
367 at an offset of @var{k} diagonals above or below the main diagonal; above\n\
368 for positive @var{k} and below for negative @var{k}.\n\
369 \n\
370 The absolute value of @var{k} must not be greater than the number of\n\
371 subdiagonals or superdiagonals.\n\
372 \n\
373 For example:\n\
374 \n\
375 @example\n\
376 @group\n\
377 tril (ones (3), -1)\n\
378  @result{} 0 0 0\n\
379  1 0 0\n\
380  1 1 0\n\
381 @end group\n\
382 @end example\n\
383 \n\
384 @noindent\n\
385 and\n\
386 \n\
387 @example\n\
388 @group\n\
389 tril (ones (3), 1)\n\
390  @result{} 1 1 0\n\
391  1 1 1\n\
392  1 1 1\n\
393 @end group\n\
394 @end example\n\
395 \n\
396 If the option @qcode{\"pack\"} is given as third argument, the extracted\n\
397 elements are not inserted into a matrix, but rather stacked column-wise one\n\
398 above other.\n\
399 @seealso{diag}\n\
400 @end deftypefn")
401 {
402  return do_trilu ("tril", args);
403 }
404 
405 DEFUN (triu, args, ,
406  "-*- texinfo -*-\n\
407 @deftypefn {Function File} {} triu (@var{A})\n\
408 @deftypefnx {Function File} {} triu (@var{A}, @var{k})\n\
409 @deftypefnx {Function File} {} triu (@var{A}, @var{k}, @var{pack})\n\
410 See the documentation for the @code{tril} function (@pxref{tril}).\n\
411 @seealso{tril}\n\
412 @end deftypefn")
413 {
414  return do_trilu ("triu", args);
415 }
416 
417 /*
418 %!test
419 %! a = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
420 %!
421 %! l0 = [1, 0, 0; 4, 5, 0; 7, 8, 9; 10, 11, 12];
422 %! l1 = [1, 2, 0; 4, 5, 6; 7, 8, 9; 10, 11, 12];
423 %! l2 = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
424 %! lm1 = [0, 0, 0; 4, 0, 0; 7, 8, 0; 10, 11, 12];
425 %! lm2 = [0, 0, 0; 0, 0, 0; 7, 0, 0; 10, 11, 0];
426 %! lm3 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 10, 0, 0];
427 %! lm4 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 0, 0, 0];
428 %!
429 %! assert (tril (a, -4), lm4);
430 %! assert (tril (a, -3), lm3);
431 %! assert (tril (a, -2), lm2);
432 %! assert (tril (a, -1), lm1);
433 %! assert (tril (a), l0);
434 %! assert (tril (a, 1), l1);
435 %! assert (tril (a, 2), l2);
436 
437 %!error tril ()
438 */
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:798
octave_idx_type cols(void) const
Definition: Sparse.h:264
T * data(void)
Definition: Sparse.h:509
OCTINTERP_API void print_usage(void)
Definition: defun.cc:51
octave_idx_type length(void) const
Definition: oct-obj.h:89
Definition: Range.h:31
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:44
void error(const char *fmt,...)
Definition: error.cc:476
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:507
octave_idx_type * cidx(void)
Definition: Sparse.h:531
static Array< T > do_tril(const Array< T > &a, octave_idx_type k, bool pack)
Definition: tril.cc:43
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:811
octave_idx_type rows(void) const
Definition: Array.h:313
static Array< T > do_triu(const Array< T > &a, octave_idx_type k, bool pack)
Definition: tril.cc:85
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov.cc:1414
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:337
#define ARRAYCASE(TYP)
bool is_sparse_type(void) const
Definition: ov.h:666
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:395
Sparse< T > maybe_compress(bool remove_zeros=false)
Definition: Sparse.h:469
int error_state
Definition: error.cc:101
SparseBoolMatrix sparse_bool_matrix_value(bool warn=false) const
Definition: ov.h:827
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:824
dim_vector dims(void) const
Definition: ov.h:470
double arg(double x)
Definition: lo-mappers.h:37
Handles the reference counting for all the derived classes.
Definition: Array.h:45
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:233
This is a simple wrapper template that will subclass an Array type or any later type derived from ...
Definition: Array.h:762
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:779
octave_idx_type * ridx(void)
Definition: Sparse.h:518
std::string class_name(void) const
Definition: ov.h:1049
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:820
const T * fortran_vec(void) const
Definition: Array.h:481
builtin_type_t builtin_type(void) const
Definition: ov.h:603
int length(void) const
Definition: dim-vector.h:281
octave_idx_type columns(void) const
Definition: Array.h:322
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
static Array< T > do_trilu(const Array< T > &a, octave_idx_type k, bool lower, bool pack)
Definition: tril.cc:176
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:210
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:438