1 // This is mul/mbl/mbl_mask.h
2 #ifndef mbl_mask_h_
3 #define mbl_mask_h_
4 //:
5 // \file
6 // \author Barry Skellern
7 // \brief Class representing a binary mask, and related functions
8 
9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 #include <stdexcept>
13 #include <iterator>
14 #include <string>
15 #include <iosfwd>
16 #include <cstddef>
17 #ifdef _MSC_VER
18 #  include <vcl_msvc_warnings.h>
19 #endif
20 #include <vul/vul_sprintf.h>
21 
22 
23 //: Defines a binary mask
24 // \note include vsl/vsl_vector_io.h in your client code, if your want binary io of mbl_mask
25 class mbl_mask : public std::vector<bool>
26 {
27  public:
mbl_mask()28   mbl_mask() : std::vector<bool>() {}
29   mbl_mask(unsigned n, bool val = false) : std::vector<bool>(n, val) {}
30 };
31 
32 //: Given a collection of indices, produce a collection of masks that isolate each indexed set
33 //    The input index set does not need to be zero based or continuous
34 //    The output vector of masks is sorted by corresponding index
35 //    for example: (1,4,2,1,2) will make three masks: (1,0,0,1,0), (0,0,1,0,1) and (0,1,0,0,0)
36 //    which correspond to the index sets 1,2,4
37 void mbl_masks_from_index_set(const std::vector<unsigned> & indices,
38                               std::vector<mbl_mask> & masks);
39 
40 
41 //: Replace 'true' values in B with values taken from A. size of A must match 'true' count in B
42 void mbl_mask_on_mask(const mbl_mask & A, mbl_mask & B);
43 
44 
45 //: Merge two input ranges according to a mask ('false' indicates element drawn from range 1, 'true' from range 2)
46 template <typename ForwardIterator>
mbl_mask_merge_values(const mbl_mask & mask,ForwardIterator first1,ForwardIterator last1,ForwardIterator first2,ForwardIterator last2,ForwardIterator result)47 void mbl_mask_merge_values(const mbl_mask & mask,
48                            ForwardIterator first1, ForwardIterator last1,
49                            ForwardIterator first2, ForwardIterator last2,
50                            ForwardIterator result)
51 {
52   if (std::distance(first1, last1) != (int)mask.size() || std::distance(first2, last2) != (int)mask.size())
53     throw std::out_of_range("Values and mask lengths differ");
54 
55   for (unsigned n = 0 ; first1 != last1 ; ++first1, ++first2, ++n)
56     *result++ = mask[n] ? *first2 : *first1;
57 }
58 
59 //: Apply a general logical operation between two masks
60 void mbl_mask_logic(const mbl_mask & A, mbl_mask & B, const std::string & operation);
61 
62 //: Apply an "AND" (rule 0001) logical operation between two masks
63 void mbl_mask_logic_and(const mbl_mask & A, mbl_mask & B);
64 
65 //: Apply an "OR" (rule 0111) logical operation between two masks
66 void mbl_mask_logic_or(const mbl_mask & A, mbl_mask & B);
67 
68 //: Apply an "XOR" (rule 0110) logical operation between two masks
69 void mbl_mask_logic_xor(const mbl_mask & A, mbl_mask & B);
70 
71 //: Apply a "NOR" (rule 1000) logical operation between two masks
72 void mbl_mask_logic_nor(const mbl_mask & A, mbl_mask & B);
73 
74 //: Apply an "XNOR" (rule 1001) logical operation between two masks
75 void mbl_mask_logic_xnor(const mbl_mask & A, mbl_mask & B);
76 
77 //: Apply an "NAND" (rule 1110) logical operation between two masks
78 void mbl_mask_logic_nand(const mbl_mask & A, mbl_mask & B);
79 
80 //: Apply a mask to a range of values. Result inserted at 'target'
81 template <typename ForwardIterator, typename OutputIterator>
mbl_apply_mask(const mbl_mask & mask,ForwardIterator first,ForwardIterator last,OutputIterator target)82 void mbl_apply_mask(const mbl_mask & mask, ForwardIterator first, ForwardIterator last, OutputIterator target)
83 {
84   if (std::distance(first, last) != (int)mask.size())
85     throw std::out_of_range("Values and mask lengths differ");
86 
87   for (unsigned n = 0; first != last ; ++first, ++n)
88     if (mask[n]) *target++ = *first;
89 }
90 
91 //: Apply a mask to a vector, returning a new vector
92 // This can be inefficient. See mbl_apply_mask(mask, src, dst)  for an alternative.
93 template <typename T>
mbl_apply_mask(const mbl_mask & mask,const std::vector<T> & values)94 std::vector<T> mbl_apply_mask(const mbl_mask & mask, const std::vector<T> & values)
95 {
96   std::vector<T> retval(values);
97   mbl_apply_mask(mask, retval);
98   return retval;
99 }
100 
101 //: Apply a mask to a vector, returning a new vector
102 // \param mask The mask to apply.
103 // \param src The source vector.
104 // \retval dst The destination vector (existing contents will be lost).
105 template <typename T>
mbl_apply_mask(const mbl_mask & mask,const std::vector<T> & src,std::vector<T> & dst)106 void mbl_apply_mask(const mbl_mask & mask, const std::vector<T> & src, std::vector<T> & dst)
107 {
108   const unsigned n_in = src.size();
109   if (mask.size() != n_in)
110   {
111     throw std::out_of_range(vul_sprintf("src and mask lengths differ: src %d mask %d",n_in,mask.size()));
112   }
113 
114   dst.clear();
115   dst.reserve(n_in); // this is the maximum size we might need
116   for (unsigned i=0; i<n_in; ++i)
117   {
118     if (mask[i])
119     {
120       dst.push_back(src[i]);
121     }
122   }
123 }
124 
125 //: Use a mask to replace some values in a vector
126 // \param mask The mask to apply.
127 // \param src1 The source vector to be updated.
128 // \param src2 The source vector to be updated with.
129 // \retval dst The destination vector (existing contents will be lost).
130 template <typename T>
mbl_replace_using_mask(const mbl_mask & mask,const std::vector<T> & src1,const std::vector<T> & src2,std::vector<T> & dst)131 void mbl_replace_using_mask(const mbl_mask & mask, const std::vector<T> & src1, const std::vector<T> & src2, std::vector<T> & dst)
132 {
133   const unsigned n_in = src1.size();
134   if (mask.size() != n_in)
135     throw std::out_of_range("src1 and mask lengths differ");
136 
137   std::size_t n_true = std::count( mask.begin(), mask.end(), true );
138   if ( n_true != src2.size() )
139     throw std::out_of_range("src2 and mask are not compatible");
140 
141   std::vector<T> dst_tmp;
142   dst_tmp.clear();
143   dst_tmp.reserve(n_in); // this is the maximum size we might need
144   unsigned j = 0;
145   for (unsigned i=0; i<n_in; ++i)
146   {
147     if (mask[i])
148     {
149       dst_tmp.push_back(src2[j]);
150       ++j;
151     }
152     else
153       dst_tmp.push_back(src1[i]);
154   }
155   dst = dst_tmp;
156 }
157 
158 //: Apply a mask to a vector in-place
159 template <typename T>
mbl_apply_mask(const mbl_mask & mask,std::vector<T> & values)160 void mbl_apply_mask(const mbl_mask & mask, std::vector<T> & values)
161 {
162   const unsigned n_in = values.size();
163   if (mask.size() != n_in)
164     throw std::out_of_range("Values and mask lengths differ");
165 
166   unsigned n_out = 0;
167   for (unsigned i = 0 ; i < n_in ; ++i)
168   {
169     if (mask[i])
170     {
171       values[n_out] = values[i];
172       ++n_out;
173     }
174   }
175   values.resize(n_out);
176 }
177 
178 //: Save to file
179 void mbl_save_mask(const mbl_mask & mask, std::ostream & stream);
180 
181 //: Save to file
182 void mbl_save_mask(const mbl_mask & mask, const char * filename);
183 
184 //: Save to file
185 void mbl_save_mask(const mbl_mask & mask, const std::string &filename);
186 
187 //: Load from file
188 void mbl_load_mask(mbl_mask & mask, std::istream & stream);
189 
190 //: Load from file
191 void mbl_load_mask(mbl_mask & mask, const char * filename);
192 
193 //: Load from file
194 void mbl_load_mask(mbl_mask & mask, const std::string &filename);
195 
196 //: Convert a mask to a list of indices.
197 // \param mask Input mask.
198 // \retval inds List of (zero-based) indices i where mask[i]==true.
199 void mbl_mask_to_indices(const mbl_mask& mask, std::vector<unsigned>& inds);
200 
201 //: Convert a list of indices to a mask.
202 // \param inds List of (zero-based) indices.
203 // \param n The length of the output mask.
204 // \retval mask Output mask. mask[i]==true for all i in \a inds
205 void mbl_indices_to_mask(const std::vector<unsigned>& inds,
206                          const unsigned n,
207                          mbl_mask& mask);
208 
209 
210 
211 
212 #endif // mbl_mask_h_
213