GNU Octave  6.2.0
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-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 
32 #include "Array.h"
33 #include "MArray.h"
34 #include "f77-fcn.h"
35 #include "oct-convn.h"
36 
37 // 2d convolution with a matrix kernel.
38 template <typename T, typename R>
39 static void
40 convolve_2d (const T *a, F77_INT ma, F77_INT na,
41  const R *b, F77_INT mb, F77_INT nb,
42  T *c, bool inner);
43 
44 // Forward instances to our Fortran implementations.
45 #define FORWARD_IMPL(T_CXX, R_CXX, T, R, T_CAST, T_CONST_CAST, \
46  R_CONST_CAST, f, F) \
47  extern "C" \
48  F77_RET_T \
49  F77_FUNC (f##conv2o, F##CONV2O) (const F77_INT&, const F77_INT&, \
50  const T*, const F77_INT&, \
51  const F77_INT&, const R*, T *); \
52  \
53  extern "C" \
54  F77_RET_T \
55  F77_FUNC (f##conv2i, F##CONV2I) (const F77_INT&, const F77_INT&, \
56  const T*, const F77_INT&, \
57  const F77_INT&, const R*, T *); \
58  \
59  template <> void \
60  convolve_2d<T_CXX, R_CXX> (const T_CXX *a, F77_INT ma, F77_INT na, \
61  const R_CXX *b, F77_INT mb, F77_INT nb, \
62  T_CXX *c, bool inner) \
63  { \
64  if (inner) \
65  F77_XFCN (f##conv2i, F##CONV2I, (ma, na, T_CONST_CAST (a), \
66  mb, nb, R_CONST_CAST (b), \
67  T_CAST (c))); \
68  else \
69  F77_XFCN (f##conv2o, F##CONV2O, (ma, na, T_CONST_CAST (a), \
70  mb, nb, R_CONST_CAST (b), \
71  T_CAST (c))); \
72  }
73 
74 FORWARD_IMPL (double, double, F77_DBLE, F77_DBLE, , , , d, D)
75 FORWARD_IMPL (float, float, F77_REAL, F77_REAL, , , , s, S)
76 
77 FORWARD_IMPL (std::complex<double>, std::complex<double>,
80 FORWARD_IMPL (std::complex<float>, std::complex<float>,
83 
84 FORWARD_IMPL (std::complex<double>, double,
86  F77_CONST_DBLE_CMPLX_ARG, , zd, ZD)
87 FORWARD_IMPL (std::complex<float>, float, F77_CMPLX, F77_REAL, F77_CMPLX_ARG,
88  F77_CONST_CMPLX_ARG, , cs, CS)
89 
90 template <typename T, typename R>
91 void convolve_nd (const T *a, const dim_vector& ad, const dim_vector& acd,
92  const R *b, const dim_vector& bd, const dim_vector& bcd,
93  T *c, const dim_vector& ccd, int nd, bool inner)
94 {
95  if (nd == 2)
96  {
97  F77_INT ad0 = octave::to_f77_int (ad(0));
98  F77_INT ad1 = octave::to_f77_int (ad(1));
99 
100  F77_INT bd0 = octave::to_f77_int (bd(0));
101  F77_INT bd1 = octave::to_f77_int (bd(1));
102 
103  convolve_2d<T, R> (a, ad0, ad1, b, bd0, bd1, c, inner);
104  }
105  else
106  {
107  octave_idx_type ma = acd(nd-2);
108  octave_idx_type na = ad(nd-1);
109  octave_idx_type mb = bcd(nd-2);
110  octave_idx_type nb = bd(nd-1);
111  octave_idx_type ldc = ccd(nd-2);
112 
113  if (inner)
114  {
115  for (octave_idx_type ja = 0; ja < na - nb + 1; ja++)
116  for (octave_idx_type jb = 0; jb < nb; jb++)
117  convolve_nd<T, R> (a + ma*(ja+jb), ad, acd,
118  b + mb*(nb-jb-1), bd, bcd,
119  c + ldc*ja, ccd, nd-1, inner);
120  }
121  else
122  {
123  for (octave_idx_type ja = 0; ja < na; ja++)
124  for (octave_idx_type jb = 0; jb < nb; jb++)
125  convolve_nd<T, R> (a + ma*ja, ad, acd, b + mb*jb, bd, bcd,
126  c + ldc*(ja+jb), ccd, nd-1, inner);
127  }
128  }
129 }
130 
131 // Arbitrary convolutor.
132 // The 2nd array is assumed to be the smaller one.
133 template <typename T, typename R>
134 static MArray<T>
135 convolve (const MArray<T>& a, const MArray<R>& b,
136  convn_type ct)
137 {
138  if (a.isempty () || b.isempty ())
139  return MArray<T> ();
140 
141  int nd = std::max (a.ndims (), b.ndims ());
142  const dim_vector adims = a.dims ().redim (nd);
143  const dim_vector bdims = b.dims ().redim (nd);
144  dim_vector cdims = dim_vector::alloc (nd);
145 
146  for (int i = 0; i < nd; i++)
147  {
148  if (ct == convn_valid)
149  cdims(i) = std::max (adims(i) - bdims(i) + 1,
150  static_cast<octave_idx_type> (0));
151  else
152  cdims(i) = std::max (adims(i) + bdims(i) - 1,
153  static_cast<octave_idx_type> (0));
154  }
155 
156  MArray<T> c (cdims, T ());
157 
158  // "valid" shape can sometimes result in empty matrices which must avoid
159  // calling Fortran code which does not expect this (bug #52067)
160  if (c.isempty ())
161  return c;
162 
163  convolve_nd<T, R> (a.fortran_vec (), adims, adims.cumulative (),
164  b.fortran_vec (), bdims, bdims.cumulative (),
165  c.fortran_vec (), cdims.cumulative (),
166  nd, ct == convn_valid);
167 
168  if (ct == convn_same)
169  {
170  // Pick the relevant part.
171  Array<idx_vector> sidx (dim_vector (nd, 1));
172 
173  for (int i = 0; i < nd; i++)
174  sidx(i) = idx_vector::make_range (bdims(i)/2, 1, adims(i));
175  c = c.index (sidx);
176  }
177 
178  return c;
179 }
180 
181 #define CONV_DEFS(TPREF, RPREF) \
182  TPREF ## NDArray \
183  convn (const TPREF ## NDArray& a, const RPREF ## NDArray& b, \
184  convn_type ct) \
185  { \
186  return convolve (a, b, ct); \
187  } \
188  TPREF ## Matrix \
189  convn (const TPREF ## Matrix& a, const RPREF ## Matrix& b, \
190  convn_type ct) \
191  { \
192  return convolve (a, b, ct); \
193  } \
194  TPREF ## Matrix \
195  convn (const TPREF ## Matrix& a, const RPREF ## ColumnVector& c, \
196  const RPREF ## RowVector& r, convn_type ct) \
197  { \
198  return convolve (a, c * r, ct); \
199  }
200 
204 CONV_DEFS (Float, Float)
205 CONV_DEFS (FloatComplex, Float)
#define C(a, b)
Definition: Faddeeva.cc:246
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:128
Array< T > index(const idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:698
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
int ndims(void) const
Size of the specified dimension.
Definition: Array.h:589
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:572
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:63
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
static dim_vector alloc(int n)
Definition: dim-vector.h:281
dim_vector cumulative(void) const
Return cumulative dimensions.
Definition: dim-vector.h:554
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:245
static idx_vector make_range(octave_idx_type start, octave_idx_type step, octave_idx_type len)
Definition: idx-vector.h:483
#define F77_CONST_CMPLX_ARG(x)
Definition: f77-fcn.h:312
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:315
float F77_REAL
Definition: f77-fcn.h:302
#define F77_CMPLX_ARG(x)
Definition: f77-fcn.h:309
double F77_DBLE
Definition: f77-fcn.h:301
double _Complex F77_DBLE_CMPLX
Definition: f77-fcn.h:303
octave_f77_int_type F77_INT
Definition: f77-fcn.h:305
#define F77_CONST_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:318
float _Complex F77_CMPLX
Definition: f77-fcn.h:304
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
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
#define CONV_DEFS(TPREF, RPREF)
Definition: oct-convn.cc:179
static MArray< T > convolve(const MArray< T > &a, const MArray< R > &b, convn_type ct)
Definition: oct-convn.cc:133
#define FORWARD_IMPL(T_CXX, R_CXX, T, R, T_CAST, T_CONST_CAST, R_CONST_CAST, f, F)
Definition: oct-convn.cc:45
R 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:89
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)
convn_type
Definition: oct-convn.h:49
@ convn_valid
Definition: oct-convn.h:52
@ convn_same
Definition: oct-convn.h:51