STIR 6.5.0
ArrayFunction.inl
Go to the documentation of this file.
1/*
2 Copyright (C) 2000 PARAPET partners
3 Copyright (C) 2000- 2007, Hammersmith Imanet Ltd
4 Copyright (C) 2026, University Medical Center Groningen
5 This file is part of STIR.
6
7 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
8
9 See STIR/LICENSE.txt for details
10*/
27#include "stir/modulo.h"
28
29#include <cmath>
30#include <complex>
31#ifdef BOOST_NO_STDC_NAMESPACE
32namespace std
33{
34using ::log;
35using ::exp;
36} // namespace std
37#endif
38
39START_NAMESPACE_STIR
40
41//----------------------------------------------------------------------
42// element wise and in place numeric functions
43//----------------------------------------------------------------------
44
45template <class elemT>
46inline Array<1, elemT>&
48{
49 for (int i = v.get_min_index(); i <= v.get_max_index(); i++)
50 v[i] = std::log(v[i]);
51 return v;
52}
53
54template <int num_dimensions, class elemT>
55inline Array<num_dimensions, elemT>&
57{
58 for (int i = v.get_min_index(); i <= v.get_max_index(); i++)
59 in_place_log(v[i]);
60 return v;
61}
62
63template <class elemT>
64inline Array<1, elemT>&
66{
67 for (int i = v.get_min_index(); i <= v.get_max_index(); i++)
68 v[i] = std::exp(v[i]);
69 return v;
70}
71
72template <int num_dimensions, class elemT>
73inline Array<num_dimensions, elemT>&
75{
76 for (int i = v.get_min_index(); i <= v.get_max_index(); i++)
77 in_place_exp(v[i]);
78 return v;
79}
80
81template <class elemT>
82inline Array<1, elemT>&
84{
85 for (int i = v.get_min_index(); i <= v.get_max_index(); i++)
86 if (v[i] < 0)
87 v[i] = -v[i];
88 return v;
89}
90
91template <int num_dimensions, class elemT>
92inline Array<num_dimensions, elemT>&
94{
95 for (int i = v.get_min_index(); i <= v.get_max_index(); i++)
96 in_place_abs(v[i]);
97 return v;
98}
99
100template <class T, class FUNCTION>
101inline T&
102in_place_apply_function(T& v, FUNCTION f)
103{
104 typename T::full_iterator iter = v.begin_all();
105 const typename T::full_iterator end_iter = v.end_all();
106 while (iter != end_iter)
107 {
108 *iter = f(*iter);
109 ++iter;
110 }
111 return v;
112}
113
114template <int num_dim, typename elemT, typename FunctionObjectPtr>
115inline void
117{
118 assert(array.is_regular());
119 const int outer_min_index = array.get_min_index();
120 const int outer_max_index = array.get_max_index();
121
122 // construct a vector with a full_iterator for every array[i]
124#ifndef _MSC_VER
125 typename
126#endif
127 Array<num_dim - 1, elemT>::full_iterator>
128 full_iterators(outer_min_index, outer_max_index);
129 for (int i = outer_min_index; i <= outer_max_index; ++i)
130 full_iterators[i] = array[i].begin_all();
131
132 // allocate 1d array
133 Array<1, elemT> array1d(outer_min_index, outer_max_index);
134
135 while (full_iterators[outer_min_index] != array[outer_min_index].end_all())
136 {
137 // copy elements into 1d array
138 for (int i = outer_min_index; i <= outer_max_index; ++i)
139 array1d[i] = *full_iterators[i];
140
141 // apply function
142 (*f)(array1d);
143
144 // put results back
145 // and increment full_iterators to do next index
146 for (int i = outer_min_index; i <= outer_max_index; ++i)
147 *full_iterators[i]++ = array1d[i];
148 }
149}
150
151template <int num_dim, typename elemT, typename FunctionObjectPtr>
152inline void
154{
155 assert(in_array.is_regular());
156 assert(out_array.is_regular());
157 const int in_min_index = in_array.get_min_index();
158 const int in_max_index = in_array.get_max_index();
159 const int out_min_index = out_array.get_min_index();
160 const int out_max_index = out_array.get_max_index();
161
162 // construct a vector with a full_iterator for every in_array[i]
163 VectorWithOffset<typename Array<num_dim - 1, elemT>::const_full_iterator> in_full_iterators(in_min_index, in_max_index);
164 for (int i = in_min_index; i <= in_max_index; ++i)
165 in_full_iterators[i] = in_array[i].begin_all();
166 // same for out_array[i]
167 VectorWithOffset<typename Array<num_dim - 1, elemT>::full_iterator> out_full_iterators(out_min_index, out_max_index);
168 for (int i = out_min_index; i <= out_max_index; ++i)
169 out_full_iterators[i] = out_array[i].begin_all();
170
171 // allocate 1d array
172 Array<1, elemT> in_array1d(in_min_index, in_max_index);
173 Array<1, elemT> out_array1d(out_min_index, out_max_index);
174
175 while (in_full_iterators[in_min_index] != in_array[in_min_index].end_all())
176 {
177 assert(out_full_iterators[out_min_index] != out_array[out_min_index].end_all());
178 // copy elements into 1d array
179 // increment in_full_iterators for next index
180 for (int i = in_min_index; i <= in_max_index; ++i)
181 in_array1d[i] = *(in_full_iterators[i]++);
182
183 // apply function
184 (*f)(out_array1d, in_array1d);
185 assert(out_array1d.get_min_index() == out_min_index);
186 assert(out_array1d.get_max_index() == out_max_index);
187
188 // put results back
189 // increment out_full_iterators for next index
190 for (int i = out_min_index; i <= out_max_index; ++i)
191 *(out_full_iterators[i]++) = out_array1d[i];
192 }
193 assert(out_full_iterators[out_min_index] == out_array[out_min_index].end_all());
194}
195
196template <int num_dim, typename elemT, typename FunctionObjectPtrIter>
197inline void
199 FunctionObjectPtrIter start,
200 FunctionObjectPtrIter stop)
201{
202 assert(start + num_dim == stop);
203 assert(num_dim > 1);
205
206 ++start;
207 for (typename Array<num_dim, elemT>::iterator restiter = array.begin(); restiter != array.end(); ++restiter)
208 in_place_apply_array_functions_on_each_index(*restiter, start, stop);
209}
210
211template <typename elemT, typename FunctionObjectPtrIter>
212inline void
213in_place_apply_array_functions_on_each_index(Array<1, elemT>& array, FunctionObjectPtrIter start, FunctionObjectPtrIter stop)
214{
215 assert(start + 1 == stop);
216 (**start)(array);
217}
218
219template <int num_dim, typename elemT, typename FunctionObjectPtrIter>
220inline void
222 const Array<num_dim, elemT>& in_array,
223 FunctionObjectPtrIter start,
224 FunctionObjectPtrIter stop)
225{
226 assert(start + num_dim == stop);
227 assert(num_dim > 1);
228
229 assert(out_array.is_regular());
230 BasicCoordinate<num_dim, int> tmp_out_min_indices, tmp_out_max_indices;
231 out_array.get_regular_range(tmp_out_min_indices, tmp_out_max_indices);
232 tmp_out_min_indices[1] = in_array.get_min_index();
233 tmp_out_max_indices[1] = in_array.get_max_index();
234 Array<num_dim, elemT> tmp_out_array(IndexRange<num_dim>(tmp_out_min_indices, tmp_out_max_indices));
235
236 for (int i = in_array.get_min_index(); i <= in_array.get_max_index(); ++i)
237 apply_array_functions_on_each_index(tmp_out_array[i], in_array[i], start + 1, stop);
238
239 apply_array_function_on_1st_index(out_array, tmp_out_array, *start);
240}
241
242// specialisation that uses ArrayFunctionObject::is_trivial etc
243template <int num_dim, typename elemT>
244inline void
246 const Array<num_dim, elemT>& in_array,
247 ActualFunctionObjectPtrIter start,
248 ActualFunctionObjectPtrIter stop)
249{
250 assert(start + num_dim == stop);
251 assert(num_dim > 1);
252
253 // cerr << "apply_array_functions_on_each_index dim " << num_dim << std::endl;
254 if ((**start).is_trivial())
255 {
256 for (int i = max(out_array.get_min_index(), in_array.get_min_index());
257 i <= min(out_array.get_max_index(), in_array.get_max_index());
258 ++i)
259 apply_array_functions_on_each_index(out_array[i], in_array[i], start + 1, stop);
260 }
261 else
262 {
263 assert(out_array.is_regular());
264
265 IndexRange<1> influencing_indices;
266 if ((**start).get_influencing_indices(influencing_indices,
267 IndexRange<1>(out_array.get_min_index(), out_array.get_max_index()))
268 == Succeeded::no)
269 influencing_indices = IndexRange<1>(influencing_indices.get_min_index(), in_array.get_max_index());
270 else
271 {
272 influencing_indices = IndexRange<1>(max(influencing_indices.get_min_index(), in_array.get_min_index()),
273 min(influencing_indices.get_max_index(), in_array.get_max_index()));
274 }
275 BasicCoordinate<num_dim, int> tmp_out_min_indices, tmp_out_max_indices;
276 out_array.get_regular_range(tmp_out_min_indices, tmp_out_max_indices);
277 tmp_out_min_indices[1] = influencing_indices.get_min_index();
278 tmp_out_max_indices[1] = influencing_indices.get_max_index();
279 Array<num_dim, elemT> tmp_out_array(IndexRange<num_dim>(tmp_out_min_indices, tmp_out_max_indices));
280
281 for (int i = influencing_indices.get_min_index(); i <= influencing_indices.get_max_index(); ++i)
282 apply_array_functions_on_each_index(tmp_out_array[i], in_array[i], start + 1, stop);
283
284 apply_array_function_on_1st_index(out_array, tmp_out_array, *start);
285 }
286}
287
288// has to be here to get general 1D specialisation to compile
289template <typename elemT>
290inline void
292 const Array<1, elemT>& in_array,
293 ActualFunctionObjectPtrIter start,
294 ActualFunctionObjectPtrIter stop)
295{
296 assert(start + 1 == stop);
297 (**start)(out_array, in_array);
298}
299
300template <typename elemT, typename FunctionObjectPtrIter>
301inline void
303 const Array<1, elemT>& in_array,
304 FunctionObjectPtrIter start,
305 FunctionObjectPtrIter stop)
306{
307 assert(start + 1 == stop);
308 (**start)(out_array, in_array);
309}
310
311/******************* functions that copy arrays using transformed indices *****/
312
313template <int num_dimensions, typename elemT>
314inline void
315transform_array_to_periodic_indices(Array<num_dimensions, elemT>& out_array, const Array<num_dimensions, elemT>& in_array)
316{
317 assert(norm(get_min_indices(out_array)) < .01); // check out_array is 0-based
318
319 BasicCoordinate<num_dimensions, int> min_indices, max_indices;
320
321 assert(out_array.get_regular_range(min_indices, max_indices));
322 out_array.get_regular_range(min_indices, max_indices);
323 const BasicCoordinate<num_dimensions, int> out_sizes = max_indices - min_indices + 1;
324 {
325 BasicCoordinate<num_dimensions, int> index = get_min_indices(in_array);
326 do
327 {
328 out_array[modulo(index, out_sizes)] = in_array[index];
329 } while (next(index, in_array));
330 }
331}
332
333template <int num_dimensions, typename elemT>
334inline void
335transform_array_from_periodic_indices(Array<num_dimensions, elemT>& out_array, const Array<num_dimensions, elemT>& in_array)
336{
337 assert(norm(get_min_indices(in_array)) < .01); // check in_array is 0-based
338
339 BasicCoordinate<num_dimensions, int> min_indices, max_indices;
340
341 assert(in_array.get_regular_range(min_indices, max_indices));
342 in_array.get_regular_range(min_indices, max_indices);
343 const BasicCoordinate<num_dimensions, int> in_sizes = max_indices - min_indices + 1;
344
345 BasicCoordinate<num_dimensions, int> index = get_min_indices(out_array);
346 do
347 {
348 out_array[index] = in_array[modulo(index, in_sizes)];
349 } while (next(index, out_array));
350}
351
352template <typename InputIt, typename elemT>
353inline void
354find_unique_values(std::set<elemT>& values, InputIt begin, InputIt end)
355{
356 for (auto iter = begin; iter != end; ++iter)
357 values.insert(*iter);
358}
359
360END_NAMESPACE_STIR
This file declares class stir::BasicCoordinate and some functions acting on stir::BasicCoordinate obj...
a variety of useful functions for indexing stir::Array objects
This class defines multi-dimensional (numeric) arrays.
Definition Array.h:78
bool is_regular() const
checks if the index range is 'regular'
Definition Array.inl:469
bool get_regular_range(BasicCoordinate< num_dimensions, int > &min, BasicCoordinate< num_dimensions, int > &max) const
find regular range, returns false if the range is not regular
Definition Array.inl:477
class BasicCoordinate<int num_dimensions, typename coordT> defines num_dimensions -dimensional coordi...
Definition BasicCoordinate.h:57
This class defines ranges which can be 'irregular'.
Definition IndexRange.h:69
A templated class for vectors, but with indices starting not from 0.
Definition VectorWithOffset.h:65
int get_max_index() const
get value of last valid index
Definition VectorWithOffset.inl:131
int get_min_index() const
get value of first valid index
Definition VectorWithOffset.inl:124
Array< 1, elemT > & in_place_abs(Array< 1, elemT > &v)
Replace elements by their absolute value, 1D version.
Definition ArrayFunction.inl:83
void in_place_apply_array_function_on_1st_index(Array< num_dim, elemT > &array, FunctionObjectPtr f)
Apply a function object on all possible 1d arrays extracted by keeping all indices fixed,...
Definition ArrayFunction.inl:116
T & in_place_apply_function(T &v, FUNCTION f)
apply any function(object) to each element of the multi-dimensional array
Definition ArrayFunction.inl:102
void apply_array_function_on_1st_index(Array< num_dim, elemT > &out_array, const Array< num_dim, elemT > &in_array, FunctionObjectPtr f)
apply any function(object) to each element of the multi-dimensional array, storing results in a diffe...
Definition ArrayFunction.inl:153
void in_place_apply_array_functions_on_each_index(Array< num_dim, elemT > &array, FunctionObjectPtrIter start, FunctionObjectPtrIter stop)
Apply a sequence of 1d array-function objects on every dimension of the input array.
Definition ArrayFunction.inl:198
void apply_array_functions_on_each_index(Array< num_dim, elemT > &out_array, const Array< num_dim, elemT > &in_array, FunctionObjectPtrIter start, FunctionObjectPtrIter stop)
Apply a sequence of 1d array-function objects on every dimension of the input array,...
Definition ArrayFunction.inl:221
Array< 1, elemT > & in_place_exp(Array< 1, elemT > &v)
Replace elements by their exponentiation, 1D version.
Definition ArrayFunction.inl:65
Array< 1, elemT > & in_place_log(Array< 1, elemT > &v)
Replace elements by their logarithm, 1D version.
Definition ArrayFunction.inl:47
double norm(const BasicCoordinate< num_dimensions, coordT > &p1)
compute sqrt(inner_product(p1,p1))
Definition BasicCoordinate.inl:426
defines stir::modulo() and related functions
BasicCoordinate< num_dimensions, int > get_min_indices(const Array< num_dimensions, T > &a)
Get the first multi-dimensional index of the array.
Definition array_index_functions.inl:100
bool next(BasicCoordinate< num_dimensions, int > &indices, const Array< num_dimensions2, T > &a)
Given an index into an array, increment it to the next one.
Definition array_index_functions.inl:107
double modulo(const double a, const double b)
Like std::fmod() but with guaranteed nonnegative result.
Definition modulo.h:52