GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-convn.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2010-2018 VZLU Prague
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <algorithm>
28 
29 #include "Array.h"
30 #include "MArray.h"
31 #include "f77-fcn.h"
32 #include "oct-convn.h"
33 
34 // 2d convolution with a matrix kernel.
35 template <typename T, typename R>
36 static void
37 convolve_2d (const T *a, F77_INT ma, F77_INT na,
38  const R *b, F77_INT mb, F77_INT nb,
39  T *c, bool inner);
40 
41 // Forward instances to our Fortran implementations.
42 #define FORWARD_IMPL(T_CXX, R_CXX, T, R, T_CAST, T_CONST_CAST, \
43  R_CONST_CAST, f, F) \
44  extern "C" \
45  F77_RET_T \
46  F77_FUNC (f##conv2o, F##CONV2O) (const F77_INT&, const F77_INT&, \
47  const T*, const F77_INT&, \
48  const F77_INT&, const R*, T *); \
49  \
50  extern "C" \
51  F77_RET_T \
52  F77_FUNC (f##conv2i, F##CONV2I) (const F77_INT&, const F77_INT&, \
53  const T*, const F77_INT&, \
54  const F77_INT&, const R*, T *); \
55  \
56  template <> void \
57  convolve_2d<T_CXX, R_CXX> (const T_CXX *a, F77_INT ma, F77_INT na, \
58  const R_CXX *b, F77_INT mb, F77_INT nb, \
59  T_CXX *c, bool inner) \
60  { \
61  if (inner) \
62  F77_XFCN (f##conv2i, F##CONV2I, (ma, na, T_CONST_CAST (a), \
63  mb, nb, R_CONST_CAST (b), \
64  T_CAST (c))); \
65  else \
66  F77_XFCN (f##conv2o, F##CONV2O, (ma, na, T_CONST_CAST (a), \
67  mb, nb, R_CONST_CAST (b), \
68  T_CAST (c))); \
69  }
70 
71 FORWARD_IMPL (double, double, F77_DBLE, F77_DBLE, , , , d, D)
72 FORWARD_IMPL (float, float, F77_REAL, F77_REAL, , , , s, S)
73 
74 FORWARD_IMPL (std::complex<double>, std::complex<double>,
77 FORWARD_IMPL (std::complex<float>, std::complex<float>,
80 
81 FORWARD_IMPL (std::complex<double>, double,
83  F77_CONST_DBLE_CMPLX_ARG, , zd, ZD)
84 FORWARD_IMPL (std::complex<float>, float, F77_CMPLX, F77_REAL, F77_CMPLX_ARG,
85  F77_CONST_CMPLX_ARG, , cs, CS)
86 
87 template <typename T, typename R>
88 void convolve_nd (const T *a, const dim_vector& ad, const dim_vector& acd,
89  const R *b, const dim_vector& bd, const dim_vector& bcd,
90  T *c, const dim_vector& ccd, int nd, bool inner)
91 {
92  if (nd == 2)
93  {
94  F77_INT ad0 = octave::to_f77_int (ad(0));
95  F77_INT ad1 = octave::to_f77_int (ad(1));
96 
97  F77_INT bd0 = octave::to_f77_int (bd(0));
98  F77_INT bd1 = octave::to_f77_int (bd(1));
99 
100  convolve_2d<T, R> (a, ad0, ad1, b, bd0, bd1, c, inner);
101  }
102  else
103  {
104  octave_idx_type ma = acd(nd-2);
105  octave_idx_type na = ad(nd-1);
106  octave_idx_type mb = bcd(nd-2);
107  octave_idx_type nb = bd(nd-1);
108  octave_idx_type ldc = ccd(nd-2);
109 
110  if (inner)
111  {
112  for (octave_idx_type ja = 0; ja < na - nb + 1; ja++)
113  for (octave_idx_type jb = 0; jb < nb; jb++)
114  convolve_nd<T, R> (a + ma*(ja+jb), ad, acd,
115  b + mb*(nb-jb-1), bd, bcd,
116  c + ldc*ja, ccd, nd-1, inner);
117  }
118  else
119  {
120  for (octave_idx_type ja = 0; ja < na; ja++)
121  for (octave_idx_type jb = 0; jb < nb; jb++)
122  convolve_nd<T, R> (a + ma*ja, ad, acd, b + mb*jb, bd, bcd,
123  c + ldc*(ja+jb), ccd, nd-1, inner);
124  }
125  }
126 }
127 
128 // Arbitrary convolutor.
129 // The 2nd array is assumed to be the smaller one.
130 template <typename T, typename R>
131 static MArray<T>
132 convolve (const MArray<T>& a, const MArray<R>& b,
133  convn_type ct)
134 {
135  if (a.isempty () || b.isempty ())
136  return MArray<T> ();
137 
138  int nd = std::max (a.ndims (), b.ndims ());
139  const dim_vector adims = a.dims ().redim (nd);
140  const dim_vector bdims = b.dims ().redim (nd);
141  dim_vector cdims = dim_vector::alloc (nd);
142 
143  for (int i = 0; i < nd; i++)
144  {
145  if (ct == convn_valid)
146  cdims(i) = std::max (adims(i) - bdims(i) + 1,
147  static_cast<octave_idx_type> (0));
148  else
149  cdims(i) = std::max (adims(i) + bdims(i) - 1,
150  static_cast<octave_idx_type> (0));
151  }
152 
153  MArray<T> c (cdims, T ());
154 
155  // "valid" shape can sometimes result in empty matrices which must avoid
156  // calling Fortran code which does not expect this (bug #52067)
157  if (c.isempty ())
158  return c;
159 
160  convolve_nd<T, R> (a.fortran_vec (), adims, adims.cumulative (),
161  b.fortran_vec (), bdims, bdims.cumulative (),
162  c.fortran_vec (), cdims.cumulative (),
163  nd, ct == convn_valid);
164 
165  if (ct == convn_same)
166  {
167  // Pick the relevant part.
168  Array<idx_vector> sidx (dim_vector (nd, 1));
169 
170  for (int i = 0; i < nd; i++)
171  sidx(i) = idx_vector::make_range (bdims(i)/2, 1, adims(i));
172  c = c.index (sidx);
173  }
174 
175  return c;
176 }
177 
178 #define CONV_DEFS(TPREF, RPREF) \
179  TPREF ## NDArray \
180  convn (const TPREF ## NDArray& a, const RPREF ## NDArray& b, \
181  convn_type ct) \
182  { \
183  return convolve (a, b, ct); \
184  } \
185  TPREF ## Matrix \
186  convn (const TPREF ## Matrix& a, const RPREF ## Matrix& b, \
187  convn_type ct) \
188  { \
189  return convolve (a, b, ct); \
190  } \
191  TPREF ## Matrix \
192  convn (const TPREF ## Matrix& a, const RPREF ## ColumnVector& c, \
193  const RPREF ## RowVector& r, convn_type ct) \
194  { \
195  return convolve (a, c * r, ct); \
196  }
198 CONV_DEFS ( , )
199 CONV_DEFS (Complex, )
201 CONV_DEFS (Float, Float)
202 CONV_DEFS (FloatComplex, Float)
double _Complex F77_DBLE_CMPLX
Definition: f77-fcn.h:303
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:32
#define C(a, b)
Definition: Faddeeva.cc:246
static MArray< T > convolve(const MArray< T > &a, const MArray< R > &b, convn_type ct)
Definition: oct-convn.cc:126
convn_type
Definition: oct-convn.h:46
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:315
dim_vector cumulative(void) const
Return cumulative dimensions.
Definition: dim-vector.h:519
STL namespace.
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Z
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
s
Definition: file-io.cc:2729
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:400
octave::call_stack & cs
Definition: ov-class.cc:1752
float _Complex F77_CMPLX
Definition: f77-fcn.h:304
void convolve_nd(const T *a, const dim_vector &ad, const dim_vector &acd, const R *b, const dim_vector &bd, const dim_vector &bcd, T *c, const dim_vector &ccd, int nd, bool inner)
Definition: oct-convn.cc:82
#define CONV_DEFS(TPREF, RPREF)
Definition: oct-convn.cc:172
static dim_vector alloc(int n)
Definition: dim-vector.h:264
static void convolve_2d(const T *a, F77_INT ma, F77_INT na, const R *b, F77_INT mb, F77_INT nb, T *c, bool inner)
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:125
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
#define F77_CMPLX_ARG(x)
Definition: f77-fcn.h:309
#define F77_CONST_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:318
octave_f77_int_type F77_INT
Definition: f77-fcn.h:305
b
Definition: cellfun.cc:400
#define F77_CONST_CMPLX_ARG(x)
Definition: f77-fcn.h:312
for i
Definition: data.cc:5264
std::complex< float > FloatComplex
Definition: oct-cmplx.h:32
std::complex< double > Complex
Definition: oct-cmplx.h:31
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
static idx_vector make_range(octave_idx_type start, octave_idx_type step, octave_idx_type len)
Definition: idx-vector.h:482
#define FORWARD_IMPL(T_CXX, R_CXX, T, R, T_CAST, T_CONST_CAST, R_CONST_CAST, f, F)
Definition: oct-convn.cc:42