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 <mbl/mbl_exception.h>
00014 
00015 
00016 
00017     //: Given a collection of indices, produce a collection of masks that isolate each indexed set
00018     //    The input index set does not need to be zero based or continuous
00019     //    The output vector of masks is sorted such that
00020     //    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)
00021     //    which correspond to the sorted index sets 1,2,4
00022 void mbl_masks_from_index_set(const vcl_vector<unsigned> & indices,
00023                               vcl_vector<mbl_mask> & masks)
00024 {
00025   masks.clear();
00026   unsigned n = indices.size(), n_masks = 0;
00027   vcl_set<unsigned> used_indices;
00028   vcl_map<unsigned, unsigned> ordering;
00029 
00030   for (unsigned i = 0 ; i < n ; ++i)
00031     used_indices.insert(indices[i]);
00032 
00033   for (vcl_set<unsigned>::const_iterator it = used_indices.begin(),
00034                                          end = used_indices.end();
00035                                          it != end; ++it)
00036   {
00037     ordering[*it] = n_masks++;
00038     masks.push_back(mbl_mask(n));
00039   }
00040 
00041   for (unsigned i = 0 ; i < n ; ++i)
00042     masks[ordering[indices[i]]][i] = true;
00043 }
00044 
00045 
00046     //: Replace 'true' values in B with values taken from A. size of A must match 'true' count in B
00047 void mbl_mask_on_mask(const mbl_mask & A, mbl_mask & B)
00048 {
00049   unsigned nA = A.size();
00050   unsigned nB = 0;
00051   for (unsigned i = 0 ; i < B.size() ; ++i) nB += B[i];
00052   if (nA != nB)
00053     throw vcl_runtime_error("Length of A mismatch with number of true elements of B");
00054 
00055   for (unsigned i = 0, j = 0 ; i < B.size() ; ++i)
00056     if (B[i]) B[i] = A[j++];
00057 }
00058 
00059 
00060     //: Apply an "AND" (rule 0001) logical operation between two masks
00061 void mbl_mask_logic_and(const mbl_mask & A, mbl_mask & B)
00062 {
00063   mbl_mask_logic(A, B, "0001");
00064 }
00065 
00066     //: Apply an "OR" (rule 0111) logical operation between two masks
00067 void mbl_mask_logic_or(const mbl_mask & A, mbl_mask & B)
00068 {
00069   mbl_mask_logic(A, B, "0111");
00070 }
00071 
00072     //: Apply an "XOR" (rule 0110) logical operation between two masks
00073 void mbl_mask_logic_xor(const mbl_mask & A, mbl_mask & B)
00074 {
00075   mbl_mask_logic(A, B, "0110");
00076 }
00077 
00078     //: Apply a "NOR" (rule 1000) logical operation between two masks
00079 void mbl_mask_logic_nor(const mbl_mask & A, mbl_mask & B)
00080 {
00081   mbl_mask_logic(A, B, "1000");
00082 }
00083 
00084     //: Apply an "XNOR" (rule 1001) logical operation between two masks
00085 void mbl_mask_logic_xnor(const mbl_mask & A, mbl_mask & B)
00086 {
00087   mbl_mask_logic(A, B, "1001");
00088 }
00089 
00090     //: Apply an "NAND" (rule 1110) logical operation between two masks
00091 void mbl_mask_logic_nand(const mbl_mask & A, mbl_mask & B)
00092 {
00093   mbl_mask_logic(A, B, "1110");
00094 }
00095 
00096 
00097     //: Apply a general logical operation between two masks
00098 void mbl_mask_logic(const mbl_mask & A, mbl_mask & B, const vcl_string & operation)
00099 {
00100   if (A.size() != B.size())
00101     throw vcl_runtime_error("Mask lengths differ");
00102 
00103   // Validate the operation to perform and parse into vector
00104 
00105   if (operation.length() != 4)
00106     throw vcl_runtime_error("Operation must be of length 4");
00107   vcl_vector<bool> op_rule(4);
00108   for (unsigned i = 0 ; i < 4 ; ++i)
00109   {
00110     if (operation[i] == '0') op_rule[i] = false;
00111     else if (operation[i] == '1') op_rule[i] = true;
00112     else throw vcl_runtime_error("Invalid character in operation string - must contain only '0' or '1'");
00113   }
00114 
00115   // Apply the operation in place
00116   for (unsigned i = 0 ; i < A.size() ; ++i)
00117     B[i] = op_rule[2*A[i] + B[i]]; // consider AB as 2bit binary, converted to decimal index into rule
00118 }
00119 
00120 
00121     //: Save to file
00122 void mbl_save_mask(const mbl_mask & mask, vcl_ostream & stream)
00123 {
00124   vcl_vector<bool>::const_iterator it = mask.begin();
00125   const vcl_vector<bool>::const_iterator & end = mask.end();
00126   for (; it != end; ++it)
00127     stream << *it << vcl_endl;
00128 }
00129 
00130     //: Save to file
00131 void mbl_save_mask(const mbl_mask & mask, const char * filename)
00132 {
00133   vcl_ofstream stream(filename);
00134   if (!stream)
00135     mbl_exception_throw_os_error(filename);
00136   mbl_save_mask(mask, stream);
00137 }
00138 
00139     //: Save to file
00140 void mbl_save_mask(const mbl_mask & mask, const vcl_string &filename)
00141 {
00142   vcl_ofstream stream(filename.c_str());
00143   if (!stream)
00144     mbl_exception_throw_os_error(filename);
00145   mbl_save_mask(mask, stream);
00146 }
00147 
00148     //: Load from file
00149 void mbl_load_mask(mbl_mask & mask, vcl_istream & stream)
00150 {
00151   mask.clear();
00152   vcl_string line;
00153   while (stream.good())
00154   {
00155     vcl_getline(stream, line);
00156     if (line.length() == 0) continue;
00157     if (line == "0") mask.push_back(false);
00158     else if (line == "1") mask.push_back(true);
00159     else
00160     {
00161       mask.clear();
00162       throw mbl_exception_parse_file_error("Unable to parse mask value " + line, "");
00163     }
00164   }
00165 }
00166 
00167     //: Load from file
00168 void mbl_load_mask(mbl_mask & mask, const char * filename)
00169 {
00170   vcl_ifstream stream(filename);
00171   if (!stream)
00172     mbl_exception_throw_os_error(filename);
00173   try
00174   {
00175     mbl_load_mask(mask, stream);
00176   }
00177   catch (mbl_exception_parse_file_error & e)
00178   {
00179     throw mbl_exception_parse_file_error(e.what(), filename);
00180   }
00181 }