1 /**********************************************************************
2 bitvec.cpp - Fast and efficient bitstring class.
3 
4 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5 Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
6 
7 This file is part of the Open Babel project.
8 For more information, see <http://openbabel.org/>
9 
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation version 2 of the License.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 ***********************************************************************/
19 #include <openbabel/babelconfig.h>
20 
21 #include <openbabel/bitvec.h>
22 #include <openbabel/oberror.h>
23 #include <cstdlib>
24 
25 namespace OpenBabel
26 {
27 
28   OBERROR extern OBMessageHandler obErrorLog;
29 
30   /*! \class OBBitVec bitvec.h <openbabel/bitvec.h>
31     \brief Fast and efficient bitstring class
32 
33     The OBBitVec class is a fast and efficient bitstring class that is
34     handy to use as a truth table. Truth tables are an easy way to store
35     whether a list of items has a particular property. Instances of
36     OBBitVec can be dynamically resized, and have a number of overloaded
37     operators that make code simple and readable. The following examples
38     demonstrate uses of the OBBitVec class:
39     \code
40     OBBitVec bv1,bv2,bv3;
41     bv1.SetBitOn(5);
42     bv2.SetBitOff(200);
43     bv1 |= bv2;
44     bv1 = bv1 & bv2;
45     if (bv1.IsEmpty()) // IsEmpty() returns true if no bits are set on
46     {
47        std::cout << "bv1 = " << bv1 << std::endl;
48     }
49 
50     int bit;
51     for (bit = bv1.NextBit(0);bit != bv1.EndBit();bit = bv1.NextBit(bit))
52     {
53        cout << "the next bit turned on is " << bit << endl;
54     }
55     \endcode
56   */
57 
58   static unsigned int bitsoff[SETWORD] =
59     {
60       0xFFFFFFFF,0xFFFFFFFE,0xFFFFFFFC,0xFFFFFFF8,0xFFFFFFF0,0xFFFFFFE0,0xFFFFFFC0,
61       0xFFFFFF80,0xFFFFFF00,0xFFFFFE00,0xFFFFFC00,0xFFFFF800,0xFFFFF000,0xFFFFE000,
62       0xFFFFC000,0xFFFF8000,0xFFFF0000,0xFFFE0000,0xFFFC0000,0xFFF80000,0xFFF00000,
63       0xFFE00000,0xFFC00000,0xFF800000,0xFF000000,0xFE000000,0xFC000000,0xF8000000,
64       0xF0000000,0xE0000000,0xC0000000,0x80000000
65     };
66 
67 #ifndef LowBit
68 #define LowBit(set, bit)                                        \
69   {int m;                                                       \
70     if (set != 0)                                               \
71       {                                                         \
72         bit = 31;                                               \
73         if (set != 0x80000000) {                                \
74           if ((m = (set & 0x0000ffff))!=0) {set = m; bit -= 16;}   \
75           if ((m = (set & 0x00ff00ff))!=0) {set = m; bit -= 8;}    \
76           if ((m = (set & 0x0f0f0f0f))!=0) {set = m; bit -= 4;}    \
77           if ((m = (set & 0x33333333))!=0) {set = m; bit -= 2;}    \
78           if ((m = (set & 0x55555555))!=0) {set = m; bit -= 1;}}}  \
79     else bit = -1;}
80 #endif
81 
82   /** Set the \p bit_offset 'th bit to 1
83     Increases the size of this bit vector if necessary
84     \param[in] bit_offset a zero based offset into the bit vector
85   */
SetBitOn(unsigned bit_offset)86   void OBBitVec::SetBitOn(unsigned bit_offset)
87   {
88     unsigned word_offset = bit_offset >> WORDROLL;
89     bit_offset &= WORDMASK;
90 
91     if (word_offset >= GetSize())
92       ResizeWords(word_offset + 1);
93     _set[word_offset] |= (1<<bit_offset);
94   }
95 
96   /** Set the \p bit_offset 'th bit to 0
97     \param[in] bit_offset a zero based offset into the bit vector
98   */
SetBitOff(unsigned bit_offset)99   void OBBitVec::SetBitOff(unsigned bit_offset)
100   {
101     unsigned word_offset = bit_offset >> WORDROLL;
102     bit_offset &= WORDMASK;
103 
104     if (word_offset < GetSize())
105       _set[word_offset] &= (~(1 << bit_offset));
106   }
107 
108   /** Set the range of bits from \p lo_bit_offset to \p hi_bit_offset to 1
109     Increases the size of this bit vector if necessary
110     \param[in] lo_bit_offset a zero based offset into the bit vector
111     \param[in] hi_bit_offset a zero based offset into the bit vector
112   */
SetRangeOn(unsigned lo_bit_offset,unsigned hi_bit_offset)113   void OBBitVec::SetRangeOn(unsigned lo_bit_offset, unsigned hi_bit_offset)
114   {
115     if (lo_bit_offset > hi_bit_offset)
116       return;
117     else if (lo_bit_offset == hi_bit_offset)
118       SetBitOn(hi_bit_offset);
119     else
120       {
121         unsigned lo_word_offset = lo_bit_offset >> WORDROLL;
122         unsigned hi_word_offset = hi_bit_offset >> WORDROLL;
123         lo_bit_offset &= WORDMASK;
124         hi_bit_offset &= WORDMASK;
125 
126         if (hi_word_offset >= GetSize())
127           ResizeWords(hi_word_offset + 1);
128 
129         if (lo_word_offset == hi_word_offset)
130           {
131             for ( unsigned i = lo_bit_offset ; i <= hi_bit_offset ; i++ )
132               _set[lo_word_offset] |= (1<<i);
133           }
134         else
135           {
136             for ( unsigned i = lo_bit_offset ; i < SETWORD ; ++ i )
137               _set[lo_word_offset] |= (1<<i);
138             for ( unsigned i = lo_word_offset + 1 ; i < hi_word_offset ; ++ i )
139               _set[i] = ~0;
140             for ( unsigned i = 0 ; i <= hi_bit_offset ; ++ i )
141               _set[hi_word_offset] |= (1<<i);
142           }
143       }
144   }
145 
146   /** Set the range of bits from \p lo_bit_offset to \p hi_bit_offset to 0
147     \param[in] lo_bit_offset a zero based offset into the bit vector
148     \param[in] hi_bit_offset a zero based offset into the bit vector
149   */
SetRangeOff(unsigned lo_bit_offset,unsigned hi_bit_offset)150   void OBBitVec::SetRangeOff(unsigned lo_bit_offset, unsigned hi_bit_offset)
151   {
152     if (lo_bit_offset > hi_bit_offset)
153       return;
154     else if (lo_bit_offset == hi_bit_offset)
155       SetBitOff(hi_bit_offset);
156     else
157       {
158         unsigned lo_word_offset = lo_bit_offset >> WORDROLL;
159         unsigned hi_word_offset = hi_bit_offset >> WORDROLL;
160         lo_bit_offset &= WORDMASK;
161         hi_bit_offset &= WORDMASK;
162 
163         if (lo_word_offset >= GetSize())
164           return;
165         if (hi_word_offset >= GetSize())
166           {
167             hi_word_offset = GetSize() - 1;
168             hi_bit_offset = SETWORD - 1;
169           }
170 
171         if (lo_word_offset == hi_word_offset)
172           {
173             for ( unsigned i = lo_bit_offset ; i <= hi_bit_offset ; ++ i )
174               _set[lo_word_offset] &= (~(1<<i));
175           }
176         else
177           {
178             for ( unsigned i = lo_bit_offset ; i < SETWORD ; ++ i )
179               _set[lo_word_offset] &= (~(1<<i));
180             for ( unsigned i = lo_word_offset + 1 ; i < hi_word_offset ; ++ i )
181               _set[i] = 0x00000000;
182             for ( unsigned i = 0 ; i <= hi_bit_offset ; ++ i )
183               _set[hi_word_offset] &= (~(1<<i));
184           }
185       }
186   }
187 
188   /** Reduce the size of the vector to \p new_bit_size
189   by or-ing the excess bits over the start of the vector
190   \param[in] new_bit_size the size of the resultant vector, in bits
191   */
Fold(unsigned new_bit_size)192   void OBBitVec::Fold(unsigned new_bit_size)
193   {
194     unsigned new_word_size = new_bit_size >> WORDROLL;
195 
196     if (_size < new_word_size)
197       {
198         ResizeWords(new_word_size);
199         return;
200       }
201 
202     for (unsigned i = 0, idx = new_word_size; idx < _size; ++idx )
203       {
204         _set[i] |= _set[idx];
205         if (i+1 < new_word_size)
206           ++i;
207         else
208           i = 0;
209       }
210     ResizeWords(new_word_size);
211   }
212 
213   /** Searches the vector for the first true value, starting at the \p last_bit_offset 'th bit
214       \param[in] last_bit_offset the bit before the first to consider
215 	    \return the bit offset of the first true bit after \p last_bit_offset, or -1 if there is none
216   */
NextBit(int last_bit_offset) const217   int OBBitVec::NextBit(int last_bit_offset) const
218   {
219     unsigned s;
220     int bit;
221     unsigned wrdcnt;
222     ++ last_bit_offset;
223 
224     wrdcnt = (unsigned)last_bit_offset >> WORDROLL;
225 
226     if (wrdcnt >= GetSize())
227       return(-1);
228 
229     if (_set[wrdcnt] != 0)
230       {
231         s = _set[wrdcnt] & bitsoff[last_bit_offset & WORDMASK];
232         if (s)
233           {
234             LowBit(s,bit);
235             if (bit != -1)
236               return(bit + (wrdcnt << WORDROLL));
237           }
238       }
239     ++ wrdcnt;
240 
241     while(wrdcnt < GetSize())
242       {
243         if (_set[wrdcnt] != 0)
244           {
245             s = _set[wrdcnt];
246             LowBit(s, bit);
247 
248             if (bit != -1)
249               return(bit + (wrdcnt << WORDROLL));
250           }
251         ++ wrdcnt;
252       }
253 
254     return(-1);
255   }
256   // Used by CountBits
257   const unsigned nibble_bit_count[0x10] =
258     {
259       0, // 0000
260       1, // 0001
261       1, // 0010
262       2, // 0011
263       1, // 0100
264       2, // 0101
265       2, // 0110
266       3, // 0111
267       1, // 1000
268       2, // 1001
269       2, // 1010
270       3, // 1011
271       2, // 1100
272       3, // 1101
273       3, // 1110
274       4  // 1111
275     };
276   /** Count the number of bits which are set in this vector
277       \return the bit count
278   */
CountBits() const279   unsigned OBBitVec::CountBits() const
280   {
281     unsigned count = 0;
282     for (word_vector::const_iterator sx = _set.begin(), sy = _set.end(); sx != sy; ++ sx)
283       {
284       uint32_t word = *sx;
285       while (word)
286         {
287         count += nibble_bit_count[word & 0xF];
288         word >>= 4;
289         }
290       }
291     return count;
292   }
293 
294 	/** Are there no bits set to 1 in this vector?
295       \return true for "is empty", false if not empty
296   */
IsEmpty() const297   bool OBBitVec::IsEmpty() const
298   {
299     for (word_vector::const_iterator sx = _set.begin(), sy = _set.end(); sx != sy; ++ sx)
300       if (* sx)
301         return(false);
302 
303     return(true);
304   }
305 
306   /** Sets bits on, listed as bit offsets
307      \param[in] bit_offsets A list of bit offsets
308   */
FromVecInt(const std::vector<int> & bit_offsets)309   void OBBitVec::FromVecInt(const std::vector<int> & bit_offsets)
310   {
311     for (std::vector<int>::const_iterator i = bit_offsets.begin(), j = bit_offsets.end(); i != j; ++i)
312       SetBitOn(* i);
313   }
314   /** Sets bits on, listed as a string of character-represented integers
315       This bit vector is first cleared.
316       The format is "[ n0 n1 n2 n3 ... ]".
317       The square brackets are optional.
318       The whitespace can be SPACE, NEWLINE or HTAB
319       For example "[ 1 5 6 9 ]"
320      \param[in] line A string containing positive integers
321      \param[in] new_bit_size The size that the vector should become
322   */
FromString(const std::string & line,int new_bit_size)323   void OBBitVec::FromString(const std::string & line, int new_bit_size)
324   {
325     size_t startpos = 0, endpos = 0;
326     std::vector<std::string> tokens;
327 
328     Clear();
329     Resize(new_bit_size); // new bits are clear
330 
331     for (;;)
332       {
333         startpos = line.find_first_not_of(" \t\r\n",startpos);
334         endpos   = line.find_first_of(" \t\r\n",startpos);
335         if (endpos == std::string::npos)
336           endpos = line.size();
337 
338         if (startpos <= line.size())
339           tokens.push_back(line.substr(startpos,endpos-startpos));
340         else
341           break;
342 
343         startpos = endpos + 1;
344       }
345 
346     for (unsigned int i = 0 ; i < tokens.size() ; i++ )
347       {
348         if ( tokens[i] == "[" )
349           continue;
350         else if ( tokens[i] == "]" )
351           break;
352 
353         int bit = atoi(tokens[i].c_str());
354 
355         if (bit >= 0)
356           SetBitOn(bit);
357         else
358           {
359             std::stringstream errorMsg;
360             errorMsg << "Negative Bit: " << bit << std::endl;
361             obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obDebug);
362           }
363       }
364   }
365 
366   /** Retrieve a list of bit offsets
367      The \p bit_offsets vector is first cleared.
368      \param[out] bit_offsets A list of bit offsets, in ascending order
369   */
ToVecInt(std::vector<int> & bit_offsets) const370   void OBBitVec::ToVecInt(std::vector<int> & bit_offsets) const
371   {
372     bit_offsets.clear();
373     bit_offsets.reserve(CountBits());
374     for (int i = NextBit(-1);i != -1;i = NextBit(i))
375       bit_offsets.push_back(i);
376   }
377 
378   /** Set all the bits in this vector to zero
379       Does not currently change the size of the vector.
380   */
Clear()381   void OBBitVec::Clear()
382   {
383     for (word_vector::iterator wx = _set.begin(), wy = _set.end(); wx != wy; ++wx)
384       * wx = 0;
385   }
386 
387   /** Assign this vector to be a copy of \p bv
388       \param[in] bv A bit vector
389       \return A reference to this
390   */
operator =(const OBBitVec & bv)391   OBBitVec & OBBitVec::operator= (const OBBitVec & bv)
392   {
393     _set = bv._set;
394     _size = _set.size();
395     return(*this);
396   }
397 
398   /** Assign this vector to the result of And-ing it with \p bv
399       \param[in] bv A bit vector
400       \return A reference to this
401   */
operator &=(const OBBitVec & bv)402   OBBitVec & OBBitVec::operator&= (const OBBitVec & bv)
403   {
404     unsigned min = (bv.GetSize() < _size) ? bv.GetSize() : _size;
405     unsigned i;
406 
407     for (i = 0;i < min;++i)
408       _set[i] &= bv._set[i];
409     for (;i < _size;++i)
410       _set[i] = 0;
411 
412     return(*this);
413   }
414 
415   /** Assign this vector to the result of Or-ing it with \p bv
416       \param[in] bv A bit vector
417       \return A reference to this
418   */
operator |=(const OBBitVec & bv)419   OBBitVec & OBBitVec::operator|= (const OBBitVec & bv)
420   {
421     if (_size < bv.GetSize())
422       ResizeWords(bv.GetSize());
423 
424     for (unsigned i = 0;i < bv.GetSize(); ++i)
425       _set[i] |= bv._set[i];
426 
427     return(*this);
428   }
429 
430   /** Assign this vector to the result of Exclusive-or-ing it with \p bv
431       \param[in] bv A bit vector
432       \return A reference to this
433   */
operator ^=(const OBBitVec & bv)434   OBBitVec & OBBitVec::operator^= (const OBBitVec & bv)
435   {
436     if (_size < bv.GetSize())
437       ResizeWords(bv.GetSize());
438 
439     for (unsigned i = 0;i < bv.GetSize(); ++i)
440       _set[i] ^= bv._set[i];
441 
442     return(*this);
443   }
444 
445   /** Unset bits in this vector which are set in \p bv
446       \param[in] bv A bit vector
447       \return A reference to this
448   */
operator -=(const OBBitVec & bv)449   OBBitVec & OBBitVec::operator-= (const OBBitVec & bv)
450   {
451     if (_size < bv.GetSize())
452       ResizeWords(bv.GetSize());
453 
454     OBBitVec tmp(*this);
455     tmp ^= bv;
456     *this &= tmp;
457     return(*this);
458   }
459 
460   /** Append vector \p bv to the end if this vector
461       \param[in] bv A bit vector
462       \return A reference to this
463   */
operator +=(const OBBitVec & bv)464   OBBitVec & OBBitVec::operator+= (const OBBitVec & bv)
465   {
466     _set.insert(_set.end(), bv._set.begin(), bv._set.end());
467     return(*this);
468   }
469 
470   /** Return a bit vector of the results of Or-ing each bit in \p bv1 with the corresponding bit in \p bv2
471       \param[in] bv1 A bit vector
472       \param[in] bv2 Another bit vector
473       \return A bit vector
474   */
operator |(const OBBitVec & bv1,const OBBitVec & bv2)475   OBBitVec operator| (const OBBitVec & bv1, const OBBitVec & bv2)
476   {
477     OBBitVec bv(bv1);
478     bv |= bv2;
479     return(bv);
480   }
481 
482   /** Return a bit vector of the results of And-ing each bit in \p bv1 with the corresponding bit in \p bv2
483       \param[in] bv1 A bit vector
484       \param[in] bv2 Another bit vector
485       \return A bit vector
486   */
operator &(const OBBitVec & bv1,const OBBitVec & bv2)487   OBBitVec operator& (const OBBitVec & bv1, const OBBitVec & bv2)
488   {
489     OBBitVec bv(bv1);
490     bv &= bv2;
491     return(bv);
492   }
493 
494   /** Return a bit vector of the results of Exclusive-or-ing each bit in \p bv1 with the corresponding bit in \p bv2
495       \param[in] bv1 A bit vector
496       \param[in] bv2 Another bit vector
497       \return A bit vector
498   */
operator ^(const OBBitVec & bv1,const OBBitVec & bv2)499   OBBitVec operator^ (const OBBitVec & bv1, const OBBitVec & bv2)
500   {
501     OBBitVec bv(bv1);
502     bv ^= bv2;
503     return(bv);
504   }
505 
506   /** Return a bit vector of the results of clearing each bit in \p bv1 which is set in \p bv2
507       \param[in] bv1 A bit vector
508       \param[in] bv2 Another bit vector
509       \return A bit vector
510   */
operator -(const OBBitVec & bv1,const OBBitVec & bv2)511   OBBitVec operator- (const OBBitVec & bv1, const OBBitVec & bv2)
512   {
513     OBBitVec bv;
514     bv = bv1 ^ bv2;
515     bv &= bv1;
516     return(bv);
517   }
518 
519   /** Return true if \p bv1 and \p bv2 are equivalent
520       Not that they may be of different size, and still equivalent provided that the extra bits are all zero.
521       \param[in] bv1 A bit vector
522       \param[in] bv2 Another bit vector
523       \return true if equal, false otherwise
524   */
operator ==(const OBBitVec & bv1,const OBBitVec & bv2)525   bool operator== (const OBBitVec & bv1, const OBBitVec & bv2)
526   {
527     if (bv1.GetSize() < bv2.GetSize())
528       { // bv1 smaller than bv2
529       unsigned i;
530       for (i = 0; i < bv1.GetSize(); ++ i)
531         if (bv1._set[i] != bv2._set[i])
532           return false;
533       for (; i < bv2.GetSize(); ++ i)
534         if (bv2._set[i] != 0)
535           return false;
536       }
537     else
538       { // bv2 smaller or equal than bv1
539       unsigned i;
540       for (i = 0; i < bv2.GetSize(); ++ i)
541         if (bv1._set[i] != bv2._set[i])
542           return false;
543       for (; i < bv1.GetSize(); ++ i)
544         if (bv1._set[i] != 0)
545           return false;
546       }
547     return true;
548   }
549 
550   /** Return true if \p bv1 i less than \p bv2
551       Lexicographical order, with bit vectors written LSB first.
552       \param[in] bv1 A bit vector
553       \param[in] bv2 Another bit vector
554       \return true if equal, false otherwise
555   */
operator <(const OBBitVec & bv1,const OBBitVec & bv2)556   bool operator< (const OBBitVec & bv1, const OBBitVec & bv2)
557   {
558     bool rtn = false;
559     int next_bit_1 = bv1.NextBit(-1);
560     int next_bit_2 = bv2.NextBit(-1);
561     bool should_continue = true;
562     while (should_continue)
563       {
564       should_continue = false;
565       if (next_bit_1 == -1)
566         rtn = (next_bit_2 == -1 ? false : true);
567       else if (next_bit_2 == -1)
568         rtn = false;
569       else if (next_bit_2 < next_bit_1)
570         rtn = true;
571       else if (next_bit_1 < next_bit_2)
572         rtn = false;
573       else
574         {
575         next_bit_1 = bv1.NextBit(next_bit_1);
576         next_bit_2 = bv2.NextBit(next_bit_2);
577         should_continue = true;
578         }
579       }
580     return rtn;
581   }
582 
583   /** Sets bits on, listed as a string of character-represented integers in a stream
584       Only reads one line of input
585       The format is "[ n0 n1 n2 n3 ... ]".
586       The square brackets are optional.
587       The whitespace can be SPACE or HTAB
588       For example "[ 1 5 6 9 ]"
589      \param[in,out] is The input stream
590      \param[out] bv The bit vector to contain the result
591   */
operator >>(std::istream & is,OBBitVec & bv)592   std::istream & operator>> ( std::istream & is, OBBitVec & bv )
593   {
594     size_t startpos = 0, endpos = 0;
595     std::vector<std::string> tokens;
596     std::string line;
597 
598     getline(is,line);
599 
600     for (;;)
601       {
602         startpos = line.find_first_not_of(" \t\r\n",startpos);
603         endpos   = line.find_first_of(" \t\r\n",startpos);
604 
605         if (endpos < line.size() && startpos <= line.size())
606           tokens.push_back(line.substr(startpos,endpos-startpos));
607         else
608           break;
609 
610         startpos = endpos + 1;
611       }
612 
613     for (unsigned int i = 0 ; i < tokens.size() ; i++ )
614       {
615         if ( tokens[i] == "[" )
616           continue;
617         else if ( tokens[i] == "]" )
618           break;
619 
620         int bit = atoi(tokens[i].c_str());
621 
622         if (bit >= 0)
623           bv.SetBitOn(bit);
624         else
625           {
626             std::stringstream errorMsg;
627             errorMsg << "Negative Bit: " << bit << std::endl;
628             obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obDebug);
629           }
630       }
631 
632     return is;
633   }
634 
635   /** Output this bit vector to a stream
636       The format is "[ n0 n1 n2 n3 ... ]".
637       The whitespace is SPACE
638       For example "[ 1 5 6 9 ]"
639      \param[out] os The output stream
640      \param[in] bv The bit vector to be output
641   */
operator <<(std::ostream & os,const OBBitVec & bv)642   std::ostream & operator<< ( std::ostream & os, const OBBitVec & bv)
643   {
644     os << "[ " << std::flush;
645 
646     for (unsigned i = 0;i < bv._size;++i)
647       for (unsigned j = 0;j < SETWORD;++j)
648         if (bv._set[i]>>(j%SETWORD)&1)
649           os << (j+(i*SETWORD)) << ' ' << std::flush;
650 
651     os << "]" << std::flush;
652     return(os);
653   }
654 
655   /** The Tanimoto coefficient may be regarded as the proportion of the "on-bits" which are shared.
656       \param[in] bv1 the first bit vector
657       \param[in] bv2 the second bit vector
658       \return the ratio of shared bits to bits which either vector has set.
659   */
Tanimoto(const OBBitVec & bv1,const OBBitVec & bv2)660   double Tanimoto(const OBBitVec & bv1, const OBBitVec & bv2)
661   {
662     OBBitVec bvtmp;
663     double andbits,orbits;
664 
665     bvtmp = bv1 & bv2;
666     andbits = (double)bvtmp.CountBits();
667     bvtmp = bv1 | bv2;
668     orbits  = (double)bvtmp.CountBits();
669 
670     return(andbits/orbits);
671   }
672 
673 } // end namespace OpenBabel
674 
675 //! \file bitvec.cpp
676 //! \brief Fast and efficient bitstring class
677 
678