Skip to content

Commit 5f8c0db

Browse files
Merge pull request #1448 from KrisThielemans/ProjDataMaths
add numerical operations to ProjData
2 parents 982a5f8 + e1086cf commit 5f8c0db

File tree

7 files changed

+344
-40
lines changed

7 files changed

+344
-40
lines changed

documentation/release_6.2.htm

+5-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ <h2> Summary for end users (also to be read by developers)</h2>
4444
<h3>New functionality</h3>
4545
<ul>
4646
<li>
47-
<code>ProjDataInMemory</code> now has same methods for numerical operations as <code>Array</code>,
48-
i.e. =,-,*,/,+=,-=,*=,/=,<code>find_max()</code>,<code>find_min()</code>,<code>sum()</code>.<br>
49-
<a href=https://github.com/UCL/STIR/pull/1439>PR #1439</a>
47+
<code>ProjData</code> now has most of the methods for numerical operations as <code>Array</code>,
48+
i.e. +=,-=,*=,/=,<code>find_max()</code>,<code>find_min()</code>,<code>sum()</code>.
49+
<code>ProjDataInMemory</code> adds =,-,*,/ (as well as overloads that are faster than the implementations
50+
in <code>ProjData</code>).<br>
51+
<a href=https://github.com/UCL/STIR/pull/1439>PR #1439</a> and <a href=https://github.com/UCL/STIR/pull/1448>PR #1448</a>
5052
</li>
5153
</ul>
5254

src/buildblock/ProjData.cxx

+162
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "stir/IO/stir_ecat7.h"
4949
#include "stir/ViewgramIndices.h"
5050
#include "stir/is_null_ptr.h"
51+
#include "stir/numerics/norm.h"
5152
#include <cstring>
5253
#include <fstream>
5354
#include <algorithm>
@@ -478,6 +479,167 @@ ProjData::sapyb(const ProjData& a, const ProjData& y, const ProjData& b)
478479
this->xapyb(*this, a, y, b);
479480
}
480481

482+
float
483+
ProjData::sum() const
484+
{
485+
double t = 0.;
486+
for (int timing_pos_num = this->get_min_tof_pos_num(); timing_pos_num <= this->get_max_tof_pos_num(); ++timing_pos_num)
487+
for (int s = this->get_min_segment_num(); s <= this->get_max_segment_num(); ++s)
488+
{
489+
const SegmentIndices ind(s, timing_pos_num);
490+
t += this->get_segment_by_sinogram(ind).sum();
491+
}
492+
return static_cast<float>(t);
493+
}
494+
495+
float
496+
ProjData::find_max() const
497+
{
498+
float t = 0;
499+
bool init = true;
500+
for (int timing_pos_num = this->get_min_tof_pos_num(); timing_pos_num <= this->get_max_tof_pos_num(); ++timing_pos_num)
501+
for (int s = this->get_min_segment_num(); s <= this->get_max_segment_num(); ++s)
502+
{
503+
const SegmentIndices ind(s, timing_pos_num);
504+
const auto t_seg = this->get_segment_by_sinogram(ind).find_max();
505+
if (init)
506+
{
507+
init = false;
508+
t = t_seg;
509+
}
510+
else
511+
{
512+
t = std::max(t, t_seg);
513+
}
514+
}
515+
return t;
516+
}
517+
518+
float
519+
ProjData::find_min() const
520+
{
521+
float t = 0;
522+
bool init = true;
523+
for (int timing_pos_num = this->get_min_tof_pos_num(); timing_pos_num <= this->get_max_tof_pos_num(); ++timing_pos_num)
524+
for (int s = this->get_min_segment_num(); s <= this->get_max_segment_num(); ++s)
525+
{
526+
const SegmentIndices ind(s, timing_pos_num);
527+
const auto t_seg = this->get_segment_by_sinogram(ind).find_min();
528+
if (init)
529+
{
530+
init = false;
531+
t = t_seg;
532+
}
533+
else
534+
{
535+
t = std::min(t, t_seg);
536+
}
537+
}
538+
return t;
539+
}
540+
541+
double
542+
ProjData::norm_squared() const
543+
{
544+
double t = 0.;
545+
for (int timing_pos_num = this->get_min_tof_pos_num(); timing_pos_num <= this->get_max_tof_pos_num(); ++timing_pos_num)
546+
for (int s = this->get_min_segment_num(); s <= this->get_max_segment_num(); ++s)
547+
{
548+
const SegmentIndices ind(s, timing_pos_num);
549+
const auto seg = this->get_segment_by_sinogram(ind);
550+
t += stir::norm_squared(seg.begin_all(), seg.end_all());
551+
}
552+
return t;
553+
}
554+
555+
double
556+
ProjData::norm() const
557+
{
558+
return std::sqrt(this->norm_squared());
559+
}
560+
561+
// static helper functions to iterate over segment and apply a function
562+
563+
// func(s1, s2) is supposed to modify s1
564+
template <typename Func>
565+
static ProjData&
566+
apply_func(ProjData& self, const ProjData& arg, Func func)
567+
{
568+
for (int timing_pos_num = self.get_min_tof_pos_num(); timing_pos_num <= self.get_max_tof_pos_num(); ++timing_pos_num)
569+
for (int s = self.get_min_segment_num(); s <= self.get_max_segment_num(); ++s)
570+
{
571+
const SegmentIndices ind(s, timing_pos_num);
572+
auto seg = self.get_segment_by_sinogram(ind);
573+
func(seg, arg.get_segment_by_sinogram(ind));
574+
self.set_segment(seg);
575+
}
576+
return self;
577+
}
578+
579+
// func(s1) is supposed to modify s1
580+
template <typename Func>
581+
static ProjData&
582+
apply_func(ProjData& self, Func func)
583+
{
584+
for (int timing_pos_num = self.get_min_tof_pos_num(); timing_pos_num <= self.get_max_tof_pos_num(); ++timing_pos_num)
585+
for (int s = self.get_min_segment_num(); s <= self.get_max_segment_num(); ++s)
586+
{
587+
const SegmentIndices ind(s, timing_pos_num);
588+
auto seg = self.get_segment_by_sinogram(ind);
589+
func(seg);
590+
self.set_segment(seg);
591+
}
592+
return self;
593+
}
594+
595+
ProjData&
596+
ProjData::operator+=(const ProjData& arg)
597+
{
598+
return apply_func(*this, arg, [](SegmentBySinogram<float>& s, const SegmentBySinogram<float>& s_arg) { s += s_arg; });
599+
}
600+
601+
ProjData&
602+
ProjData::operator-=(const ProjData& arg)
603+
{
604+
return apply_func(*this, arg, [](SegmentBySinogram<float>& s, const SegmentBySinogram<float>& s_arg) { s -= s_arg; });
605+
}
606+
607+
ProjData&
608+
ProjData::operator*=(const ProjData& arg)
609+
{
610+
return apply_func(*this, arg, [](SegmentBySinogram<float>& s, const SegmentBySinogram<float>& s_arg) { s *= s_arg; });
611+
}
612+
613+
ProjData&
614+
ProjData::operator/=(const ProjData& arg)
615+
{
616+
return apply_func(*this, arg, [](SegmentBySinogram<float>& s, const SegmentBySinogram<float>& s_arg) { s /= s_arg; });
617+
}
618+
619+
ProjData&
620+
ProjData::operator+=(float arg)
621+
{
622+
return apply_func(*this, [arg](SegmentBySinogram<float>& s) { s += arg; });
623+
}
624+
625+
ProjData&
626+
ProjData::operator-=(float arg)
627+
{
628+
return apply_func(*this, [arg](SegmentBySinogram<float>& s) { s -= arg; });
629+
}
630+
631+
ProjData&
632+
ProjData::operator*=(float arg)
633+
{
634+
return apply_func(*this, [arg](SegmentBySinogram<float>& s) { s *= arg; });
635+
}
636+
637+
ProjData&
638+
ProjData::operator/=(float arg)
639+
{
640+
return apply_func(*this, [arg](SegmentBySinogram<float>& s) { s /= arg; });
641+
}
642+
481643
std::vector<int>
482644
ProjData::standard_segment_sequence(const ProjDataInfo& pdi)
483645
{

src/buildblock/ProjDataInMemory.cxx

+22-8
Original file line numberDiff line numberDiff line change
@@ -393,30 +393,44 @@ ProjDataInMemory::norm_squared() const
393393
}
394394

395395
ProjDataInMemory&
396-
ProjDataInMemory::operator+=(const ProjDataInMemory& v)
396+
ProjDataInMemory::operator+=(const base_type& v)
397397
{
398-
this->buffer += v.buffer;
398+
if (auto vp = dynamic_cast<const ProjDataInMemory*>(&v))
399+
this->buffer += vp->buffer;
400+
else
401+
base_type::operator+=(v);
402+
399403
return *this;
400404
}
401405

402406
ProjDataInMemory&
403-
ProjDataInMemory::operator-=(const ProjDataInMemory& v)
407+
ProjDataInMemory::operator-=(const base_type& v)
404408
{
405-
this->buffer -= v.buffer;
409+
if (auto vp = dynamic_cast<const ProjDataInMemory*>(&v))
410+
this->buffer -= vp->buffer;
411+
else
412+
base_type::operator-=(v);
406413
return *this;
407414
}
408415

409416
ProjDataInMemory&
410-
ProjDataInMemory::operator*=(const ProjDataInMemory& v)
417+
ProjDataInMemory::operator*=(const base_type& v)
411418
{
412-
this->buffer *= v.buffer;
419+
if (auto vp = dynamic_cast<const ProjDataInMemory*>(&v))
420+
this->buffer *= vp->buffer;
421+
else
422+
base_type::operator*=(v);
413423
return *this;
414424
}
415425

416426
ProjDataInMemory&
417-
ProjDataInMemory::operator/=(const ProjDataInMemory& v)
427+
ProjDataInMemory::operator/=(const base_type& v)
418428
{
419-
this->buffer /= v.buffer;
429+
if (auto vp = dynamic_cast<const ProjDataInMemory*>(&v))
430+
this->buffer /= vp->buffer;
431+
else
432+
base_type::operator/=(v);
433+
420434
return *this;
421435
}
422436

src/include/stir/ProjData.h

+47
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ class ProjDataInMemory;
102102
*/
103103
class ProjData : public ExamData
104104
{
105+
#ifdef SWIG
106+
public: // SWIG needs self_type exposed
107+
#endif
108+
typedef ProjData self_type;
109+
105110
public:
106111
//! A static member to get the projection data from a file
107112
static shared_ptr<ProjData> read_from_file(const std::string& filename, const std::ios::openmode open_mode = std::ios::in);
@@ -371,6 +376,47 @@ class ProjData : public ExamData
371376
//! writes data to a file in Interfile format
372377
Succeeded write_to_file(const std::string& filename) const;
373378

379+
//! @name arithmetic operations
380+
///@{
381+
//! return sum of all elements
382+
virtual float sum() const;
383+
384+
//! return maximum value of all elements
385+
virtual float find_max() const;
386+
387+
//! return minimum value of all elements
388+
virtual float find_min() const;
389+
390+
//! return L2-norm (sqrt of sum of squares)
391+
virtual double norm() const;
392+
393+
//! return L2-norm squared (sum of squares)
394+
virtual double norm_squared() const;
395+
396+
//! adding elements of \c v to the current data
397+
virtual self_type& operator+=(const self_type& v);
398+
399+
//! subtracting elements of \c v from the current data
400+
virtual self_type& operator-=(const self_type& v);
401+
402+
//! multiplying elements of the current data with elements of \c v
403+
virtual self_type& operator*=(const self_type& v);
404+
405+
//! dividing all elements of the current data by elements of \c v
406+
virtual self_type& operator/=(const self_type& v);
407+
408+
//! adding an \c float to the elements of the current data
409+
virtual self_type& operator+=(const float v);
410+
411+
//! subtracting an \c float from the elements of the current data
412+
virtual self_type& operator-=(const float v);
413+
414+
//! multiplying the elements of the current data with an \c float
415+
virtual self_type& operator*=(const float v);
416+
417+
//! dividing the elements of the current data by an \c float
418+
virtual self_type& operator/=(const float v);
419+
374420
//! \deprecated a*x+b*y (use xapyb)
375421
STIR_DEPRECATED virtual void axpby(const float a, const ProjData& x, const float b, const ProjData& y);
376422

@@ -385,6 +431,7 @@ class ProjData : public ExamData
385431

386432
//! set values of the array to self*a+y*b where a, b and y are ProjData
387433
virtual void sapyb(const ProjData& a, const ProjData& y, const ProjData& b);
434+
///@}
388435

389436
protected:
390437
shared_ptr<const ProjDataInfo> proj_data_info_sptr;

src/include/stir/ProjDataInMemory.h

+22-21
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class ProjDataInMemory : public ProjData
4242
public:
4343
#endif
4444
typedef ProjDataInMemory self_type;
45+
typedef ProjData base_type;
4546

4647
public:
4748
//! constructor with only info, but no data
@@ -106,19 +107,19 @@ class ProjDataInMemory : public ProjData
106107
//! @name arithmetic operations
107108
///@{
108109
//! return sum of all elements
109-
float sum() const;
110+
float sum() const override;
110111

111112
//! return maximum value of all elements
112-
float find_max() const;
113+
float find_max() const override;
113114

114115
//! return minimum value of all elements
115-
float find_min() const;
116+
float find_min() const override;
116117

117118
//! return L2-norm (sqrt of sum of squares)
118-
double norm() const;
119+
double norm() const override;
119120

120121
//! return L2-norm squared (sum of squares)
121-
double norm_squared() const;
122+
double norm_squared() const override;
122123

123124
//! elem by elem addition
124125
self_type operator+(const self_type& iv) const;
@@ -146,29 +147,29 @@ class ProjDataInMemory : public ProjData
146147

147148
// corresponding assignment operators
148149

149-
//! adding elements of \c v to the current vector
150-
self_type& operator+=(const self_type& v);
150+
//! adding elements of \c v to the current data
151+
self_type& operator+=(const base_type& v) override;
151152

152-
//! subtracting elements of \c v from the current vector
153-
self_type& operator-=(const self_type& v);
153+
//! subtracting elements of \c v from the current data
154+
self_type& operator-=(const base_type& v) override;
154155

155-
//! multiplying elements of the current vector with elements of \c v
156-
self_type& operator*=(const self_type& v);
156+
//! multiplying elements of the current data with elements of \c v
157+
self_type& operator*=(const base_type& v) override;
157158

158-
//! dividing all elements of the current vector by elements of \c v
159-
self_type& operator/=(const self_type& v);
159+
//! dividing all elements of the current data by elements of \c v
160+
self_type& operator/=(const base_type& v) override;
160161

161-
//! adding an \c float to the elements of the current vector
162-
self_type& operator+=(const float v);
162+
//! adding an \c float to the elements of the current data
163+
self_type& operator+=(const float v) override;
163164

164-
//! subtracting an \c float from the elements of the current vector
165-
self_type& operator-=(const float v);
165+
//! subtracting an \c float from the elements of the current data
166+
self_type& operator-=(const float v) override;
166167

167-
//! multiplying the elements of the current vector with an \c float
168-
self_type& operator*=(const float v);
168+
//! multiplying the elements of the current data with an \c float
169+
self_type& operator*=(const float v) override;
169170

170-
//! dividing the elements of the current vector by an \c float
171-
self_type& operator/=(const float v);
171+
//! dividing the elements of the current data by an \c float
172+
self_type& operator/=(const float v) override;
172173

173174
//! \deprecated a*x+b*y (use xapyb)
174175
STIR_DEPRECATED void axpby(const float a, const ProjData& x, const float b, const ProjData& y) override;

0 commit comments

Comments
 (0)