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