contrib/mul/mbl/mbl_mask.cxx
Go to the documentation of this file.
00001 // This is mul/mbl/mbl_mask.cxx
00002 
00003 //:
00004 // \file
00005 // \author Barry Skellern
00006 // \brief Class representing a binary mask, and related functions
00007 
00008 #include "mbl_mask.h"
00009 #include <vcl_set.h>
00010 #include <vcl_map.h>
00011 #include <vcl_fstream.h>
00012 #include <vcl_string.h>
00013 #include <vul/vul_string.h>
00014 #include <mbl/mbl_exception.h>
00015 
00016 
00017 
00018     //: Given a collection of indices, produce a collection of masks that isolate each indexed set
00019     //    The input index set does not need to be zero based or continuous
00020     //    The output vector of masks is sorted such that
00021     //    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)
00022     //    which correspond to the sorted index sets 1,2,4
00023 void mbl_masks_from_index_set(const vcl_vector<unsigned> & indices,
00024                               vcl_vector<mbl_mask> & masks)
00025 {
00026   masks.clear();
00027   unsigned n = indices.size(), n_masks = 0;
00028   vcl_set<unsigned> used_indices;
00029   vcl_map<unsigned, unsigned> ordering;
00030 
00031   for (unsigned i = 0 ; i < n ; ++i)
00032     used_indices.insert(indices[i]);
00033 
00034   for (vcl_set<unsigned>::const_iterator it = used_indices.begin(),
00035                                          end = used_indices.end();
00036                                          it != end; ++it)
00037   {
00038     ordering[*it] = n_masks++;
00039     masks.push_back(mbl_mask(n));
00040   }
00041 
00042   for (unsigned i = 0 ; i < n ; ++i)
00043     masks[ordering[indices[i]]][i] = true;
00044 }
00045 
00046 
00047     //: Replace 'true' values in B with values taken from A. size of A must match 'true' count in B
00048 void mbl_mask_on_mask(const mbl_mask & A, mbl_mask & B)
00049 {
00050   unsigned nA = A.size();
00051   unsigned nB = 0;
00052   for (unsigned i = 0 ; i < B.size() ; ++i) nB += B[i];
00053   if (nA != nB)
00054     throw vcl_out_of_range("mbl_mask: Length of A mismatch with number of true elements of B");
00055 
00056   for (unsigned i = 0, j = 0 ; i < B.size() ; ++i)
00057     if (B[i]) B[i] = A[j++];
00058 }
00059 
00060 
00061     //: Apply an "AND" (rule 0001) logical operation between two masks
00062 void mbl_mask_logic_and(const mbl_mask & A, mbl_mask & B)
00063 {
00064   mbl_mask_logic(A, B, "0001");
00065 }
00066 
00067 //: Apply an "OR" (rule 0111) logical operation between two masks
00068 void mbl_mask_logic_or(const mbl_mask & A, mbl_mask & B)
00069 {
00070   mbl_mask_logic(A, B, "0111");
00071 }
00072 
00073     //: Apply an "XOR" (rule 0110) logical operation between two masks
00074 void mbl_mask_logic_xor(const mbl_mask & A, mbl_mask & B)
00075 {
00076   mbl_mask_logic(A, B, "0110");
00077 }
00078 
00079     //: Apply a "NOR" (rule 1000) logical operation between two masks
00080 void mbl_mask_logic_nor(const mbl_mask & A, mbl_mask & B)
00081 {
00082   mbl_mask_logic(A, B, "1000");
00083 }
00084 
00085     //: Apply an "XNOR" (rule 1001) logical operation between two masks
00086 void mbl_mask_logic_xnor(const mbl_mask & A, mbl_mask & B)
00087 {
00088   mbl_mask_logic(A, B, "1001");
00089 }
00090 
00091     //: Apply an "NAND" (rule 1110) logical operation between two masks
00092 void mbl_mask_logic_nand(const mbl_mask & A, mbl_mask & B)
00093 {
00094   mbl_mask_logic(A, B, "1110");
00095 }
00096 
00097 
00098     //: Apply a general logical operation between two masks
00099 void mbl_mask_logic(const mbl_mask & A, mbl_mask & B, const vcl_string & operation)
00100 {
00101   if (A.size() != B.size())
00102     throw vcl_out_of_range("mbl_mask_logic: Mask lengths differ");
00103 
00104   // Validate the operation to perform and parse into vector
00105 
00106   if (operation.length() != 4)
00107     throw vcl_length_error("mbl_mask_logic: Operation must be of length 4");
00108   vcl_vector<bool> op_rule(4);
00109   for (unsigned i = 0 ; i < 4 ; ++i)
00110   {
00111     if (operation[i] == '0') op_rule[i] = false;
00112     else if (operation[i] == '1') op_rule[i] = true;
00113     else throw vcl_invalid_argument("mbl_mask_logic: Invalid character in operation string - must contain only '0' or '1'");
00114   }
00115 
00116   // Apply the operation in place
00117   for (unsigned i = 0 ; i < A.size() ; ++i)
00118     B[i] = op_rule[2*A[i] + B[i]]; // consider AB as 2bit binary, converted to decimal index into rule
00119 }
00120 
00121 
00122     //: Save to file
00123 void mbl_save_mask(const mbl_mask & mask, vcl_ostream & stream)
00124 {
00125   vcl_vector<bool>::const_iterator it = mask.begin();
00126   const vcl_vector<bool>::const_iterator & end = mask.end();
00127   for (; it != end; ++it)
00128     stream << *it << vcl_endl;
00129 }
00130 
00131     //: Save to file
00132 void mbl_save_mask(const mbl_mask & mask, const char * filename)
00133 {
00134   vcl_ofstream stream(filename);
00135   if (!stream)
00136     mbl_exception_throw_os_error(filename);
00137   mbl_save_mask(mask, stream);
00138 }
00139 
00140     //: Save to file
00141 void mbl_save_mask(const mbl_mask & mask, const vcl_string &filename)
00142 {
00143   vcl_ofstream stream(filename.c_str());
00144   if (!stream)
00145     mbl_exception_throw_os_error(filename);
00146   mbl_save_mask(mask, stream);
00147 }
00148 
00149     //: Load from file
00150 void mbl_load_mask(mbl_mask & mask, vcl_istream & stream)
00151 {
00152   mask.clear();
00153   vcl_string line;
00154   while (stream.good())
00155   {
00156     char c='X';
00157     stream >> vcl_ws >> c;
00158     if (stream.eof()) break;
00159     if (c == '0') mask.push_back(false);
00160     else if (c == '1') mask.push_back(true);
00161     else
00162     {
00163       mask.clear();
00164       throw mbl_exception_parse_file_error(vcl_string("Unable to parse mask value " +
00165         vul_string_escape_ctrl_chars(vcl_string(1,c)) ), "" );
00166     }
00167   }
00168 }
00169 
00170     //: Load from file
00171 void mbl_load_mask(mbl_mask & mask, const char * filename)
00172 {
00173   vcl_ifstream stream(filename);
00174   if (!stream)
00175     mbl_exception_throw_os_error(filename);
00176   try
00177   {
00178     mbl_load_mask(mask, stream);
00179   }
00180   catch (mbl_exception_parse_file_error & e)
00181   {
00182     throw mbl_exception_parse_file_error(e.what(), filename);
00183   }
00184 }
00185 
00186     //: Load from file
00187 void mbl_load_mask(mbl_mask & mask, const vcl_string &filename)
00188 {
00189   mbl_load_mask( mask, filename.c_str() );
00190 }
00191 
00192 
00193 //: Convert a mask to a list of indices.
00194 void mbl_mask_to_indices(const mbl_mask& mask, vcl_vector<unsigned>& inds)
00195 {
00196   inds.clear();
00197   for (unsigned i=0,n=mask.size(); i<n; ++i)
00198   {
00199     if (mask[i]) inds.push_back(i);
00200   }
00201 }
00202 
00203 
00204 //: Convert a list of indices to a mask.
00205 void mbl_indices_to_mask(const vcl_vector<unsigned>& inds,
00206                          const unsigned n,
00207                          mbl_mask& mask)
00208 {
00209   mask.resize(n, false);
00210   for (unsigned i=0, m=inds.size(); i<m; ++i)
00211   {
00212     mask[inds[i]]=true;
00213   }
00214 }
00215 
00216 
00217 
00218