       1 package Fingerprints::Fingerprints;
       2 #
       3 # $RCSfile: Fingerprints.pm,v $
       4 # $Date: 2015/02/28 20:48:54 $
       5 # $Revision: 1.33 $
       6 #
       7 # Author: Manish Sud <msud@san.rr.com>
       8 #
       9 # Copyright (C) 2015 Manish Sud. All rights reserved.
      10 #
      11 # This file is part of MayaChemTools.
      12 #
      13 # MayaChemTools is free software; you can redistribute it and/or modify it under
      14 # the terms of the GNU Lesser General Public License as published by the Free
      15 # Software Foundation; either version 3 of the License, or (at your option) any
      16 # later version.
      17 #
      18 # MayaChemTools is distributed in the hope that it will be useful, but without
      19 # any warranty; without even the implied warranty of merchantability of fitness
      20 # for a particular purpose.  See the GNU Lesser General Public License for more
      21 # details.
      22 #
      23 # You should have received a copy of the GNU Lesser General Public License
      24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
      25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
      26 # Boston, MA, 02111-1307, USA.
      27 #
      28
      29 use strict;
      30 use Carp;
      31 use Exporter;
      32 use Scalar::Util ();
      33 use ObjectProperty;
      34 use MathUtil ();
      35 use TextUtil ();
      36 use Fingerprints::FingerprintsBitVector;
      37 use Fingerprints::FingerprintsVector;
      38
      39 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
      40
      41 @ISA = qw(ObjectProperty Exporter);
      42 @EXPORT = qw();
      43 @EXPORT_OK = qw();
      44
      45 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
      46
      47 # Setup class variables...
      48 my($ClassName);
      49 _InitializeClass();
      50
      51 # Class constructor...
      52 sub new {
      53   my($Class, %NamesAndValues) = @_;
      54
      55   # Initialize object...
      56   my $This = {};
      57   bless $This, ref($Class) || $Class;
      58   $This->_InitializeFingerprints();
      59
      60   $This->_InitializeFingerprintsProperties(%NamesAndValues);
      61
      62   return $This;
      63 }
      64
      65 # Initialize object data...
      66 #
      67 sub _InitializeFingerprints {
      68   my($This) = @_;
      69
      70   # Molecule object...
      71   $This->{Molecule} = '';
      72
      73   # Type of fingerprints...
      74   $This->{Type} = '';
      75
      76   # Type of fingerprints vector: FingerprintsBitVector or FingerprintsVector...
      77   $This->{VectorType} = '';
      78
      79   # Marks successful generation of fingerprints...
      80   $This->{FingerprintsGenerated} = 0;
      81
      82   # Initialize values for FingerprintsBitVector...
      83   _InitializeClassValuesForFingerprintsBitVector();
      84
      85   # Initialize values for FingerprintsVector...
      86   _InitializeClassValuesForFingerprintsVector();
      87 }
      88
      89 # Initialize class ...
      90 sub _InitializeClass {
      91   #Class name...
      92   $ClassName = __PACKAGE__;
      93 }
      94
      95 # Initialize class values specific to FingerprintsBitVector...
      96 #
      97 sub _InitializeClassValuesForFingerprintsBitVector {
      98   my($This) = @_;
      99
     100   # Size of FingerprintsBitVector...
     101   $This->{Size} = '';
     102
     103   # Min/Max sizes used for folding FingerprintsBitVector...
     104   $This->{MinSize} = '';
     105   $This->{MaxSize} = '';
     106
     107   # FingerprintsBitVector...
     108   $This->{FingerprintsBitVector} = '';
     109 }
     110
     111 # Initialize class values specific to FingerprintsVector...
     112 #
     113 sub _InitializeClassValuesForFingerprintsVector {
     114   my($This) = @_;
     115
     116   # Types of FingerprintsVector values: OrderedNumericalValues, NumericalValues or AlphaNumericalValues.
     117   $This->{FingerprintsVectorType} = '';
     118
     119   # Fingerprints vector...
     120   $This->{FingerprintsVector} = '';
     121 }
     122
     123 # Initialize object properties....
     124 sub _InitializeFingerprintsProperties {
     125   my($This, %NamesAndValues) = @_;
     126
     127   my($Name, $Value, $MethodName);
     128   while (($Name, $Value) = each  %NamesAndValues) {
     129     $MethodName = "Set${Name}";
     130     $This->$MethodName($Value);
     131   }
     132
     133   return $This;
     134 }
     135
     136 # Set molecule object and make sure it's not already set...
     137 #
     138 sub SetMolecule {
     139   my($This, $Molecule) = @_;
     140
     141   if ($This->{Molecule}) {
     142     croak "Error: ${ClassName}->SetMolecule: Can't change molecule object:  It's already set...";
     143   }
     144   $This->{Molecule} = $Molecule;
     145
     146   # Weaken the reference to disable increment of reference count...
     147   Scalar::Util::weaken($This->{Molecule});
     148
     149   return $This;
     150 }
     151
     152 # Set type and make sure it's not already set...
     153 #
     154 sub SetType {
     155   my($This, $Type) = @_;
     156
     157   if ($This->{Type}) {
     158     croak "Error: ${ClassName}->SetType: Can't change fingerprint type:  It's already set...";
     159   }
     160   $This->{Type} = $Type;
     161
     162   return $This;
     163 }
     164
     165 # Is fingerprints generation successful?
     166 #
     167 # Notes:
     168 #   . The specific fingerprints generation class sets the value of FingerprinsGenerated
     169 #     to 1 after the successful generation of fingerprints; otherwise, it's set to 0.
     170 #
     171 sub IsFingerprintsGenerationSuccessful {
     172   my($This) = @_;
     173
     174   return $This->{FingerprintsGenerated} ? 1 : 0;
     175 }
     176
     177 # Set vector type and make sure it's not already set...
     178 #
     179 sub SetVectorType {
     180   my($This, $VectorType) = @_;
     181
     182   if ($This->{VectorType}) {
     183     croak "Error: ${ClassName}->SetVectorType: Can't change fingerprint vector type:  It's already set...";
     184   }
     185   if ($VectorType !~ /^(FingerprintsBitVector|FingerprintsVector)$/i) {
     186     croak "Error: ${ClassName}->SetVectorType: Specified value, $VectorType, for Type is not vaild. Supported types in current release of MayaChemTools: FingerprintsBitVector and FingerprintsVector...";
     187   }
     188   $This->{VectorType} = $VectorType;
     189
     190   return $This;
     191 }
     192
     193 #
     194 # Methods/functions for FingerprintsBitVector...
     195 #
     196
     197 # Initialize fingerprint bit vector...
     198 sub _InitializeFingerprintsBitVector {
     199   my($This) = @_;
     200
     201   if ($This->{VectorType} !~ /^FingerprintsBitVector$/i) {
     202     croak "Error: ${ClassName}->_InitializeFingerprintsBitVector: Can't initialize fingerprints bit vector: VectorType must be FingerprintsBitVector...";
     203   }
     204
     205   if ($This->{Size}) {
     206     $This->{FingerprintsBitVector} = new Fingerprints::FingerprintsBitVector($This->{Size});
     207   }
     208   return $This;
     209 }
     210
     211 # Set size...
     212 #
     213 sub SetSize {
     214   my($This, $Size) = @_;
     215
     216   if ($This->{MinSize} && $Size < $This->{MinSize}) {
     217     croak "Error: ${ClassName}->SetSize: Fingerprint size value, $Size, is not valid :  It must be >= $This->{MinSize}...";
     218   }
     219   if ($This->{MaxSize} && $Size > $This->{MaxSize}) {
     220     croak "Error: ${ClassName}->SetSize: Fingerprint size value, $Size, is not valid:  It must be <= $This->{MaxSize}...";
     221   }
     222
     223   $This->{Size} = $Size;
     224
     225   return $This;
     226 }
     227
     228 # Set FingerprintsBitVector object and make sure it's not already set...
     229 #
     230 sub SetFingerprintsBitVector {
     231   my($This, $FingerprintsBitVector) = @_;
     232
     233   if ($This->{FingerprintsBitVector}) {
     234     croak "Error: ${ClassName}->SetFingerprintsBitVector: Can't change FingerprintsBitVector object:  It's already set...";
     235   }
     236   $This->{FingerprintsBitVector} = $FingerprintsBitVector;
     237
     238   return $This;
     239 }
     240
     241 # Fold fingerprints by recursively reducing its size by half untill bit density is greater than or equal to
     242 # specified bit density...
     243 #
     244 sub FoldFingerprintsByBitDensity {
     245   my($This, $BitDensity) = @_;
     246
     247   if (!($BitDensity >= 0 && $BitDensity <= 1)) {
     248     croak "Error: ${ClassName}->FoldFingerprintsByBitDensity: Specified bit density, $BitDensity, is not valid:  It must be > 0 && <= 1 ...";
     249   }
     250
     251   return $This->_FoldFingerprintsBitVector('ByDensity', $BitDensity);
     252 }
     253
     254 # Fold fingerprints by recursively reducing its size by half untill size is less than or equal to
     255 # specified size...
     256 #
     257 sub FoldFingerprintsBySize {
     258   my($This, $Size, $CheckSizeValue) = @_;
     259
     260   if (!defined $CheckSizeValue) {
     261     $CheckSizeValue = 1;
     262   }
     263
     264   if ($CheckSizeValue) {
     265     if (!TextUtil::IsPositiveInteger($Size)) {
     266       croak "Error: ${ClassName}->FoldFingerprintsBySize: Specified size, $Size, is not valid:  It must be a positive integer";
     267     }
     268     if (!($Size >= $This->{MinSize} && $Size < $This->{Size})) {
     269       croak "Error: ${ClassName}->FoldFingerprintsBySize: Specified size, $Size, is not valid:  It must be greater than or equal to minimum size of $This->{MinSize} and less than current size of $This->{Size}...";
     270     }
     271     if (!TextUtil::IsNumberPowerOfNumber($Size, 2)) {
     272       croak "Error: ${ClassName}->FoldFingerprintsBySize: Specified size value, $Size, must be power of 2...";
     273     }
     274   }
     275
     276   return $This->_FoldFingerprintsBitVector('BySize', $Size);
     277 }
     278
     279 # Fold fingerprints bit vector using specified size of bit density...
     280 #
     281 sub _FoldFingerprintsBitVector {
     282   my($This, $Mode, $Value) = @_;
     283
     284   if (!$This->{FingerprintsBitVector}) {
     285     return $This;
     286   }
     287   my($FingerprintsBitVector, $FoldedFingerprintsBitVector);
     288
     289   $FoldedFingerprintsBitVector = '';
     290   $FingerprintsBitVector = $This->{FingerprintsBitVector};
     291   MODE: {
     292     if ($Mode =~ /^BySize$/i) { $FoldedFingerprintsBitVector = $FingerprintsBitVector->FoldFingerprintsBitVectorBySize($Value); last MODE; }
     293     if ($Mode =~ /^ByDensity$/i) { $FoldedFingerprintsBitVector = $FingerprintsBitVector->FoldFingerprintsBitVectorByDensity($Value); last MODE; }
     294     $FoldedFingerprintsBitVector = '';
     295   }
     296   if ($FoldedFingerprintsBitVector) {
     297     $This->{FingerprintsBitVector} = $FoldedFingerprintsBitVector;
     298     $This->{Size} = $FoldedFingerprintsBitVector->GetSize();
     299   }
     300   return $This;
     301 }
     302
     303 # Get fingerprints as a binary ascii string containing 0s and 1s...
     304 #
     305 sub GetFingerprintBitsAsBinaryString {
     306   my($This, $BitOrder) = @_;
     307
     308   return $This->_GetFingerprintBitsAsString('Binary', $BitOrder);
     309 }
     310
     311 # Get fingerprints as a hexadecimal string...
     312 #
     313 sub GetFingerprintBitsAsHexadecimalString {
     314   my($This, $BitOrder) = @_;
     315
     316   return $This->_GetFingerprintBitsAsString('Hexadecimal', $BitOrder);
     317 }
     318
     319 # Get fingerprints as a raw binary string containing packed bit values for each
     320 # byte...
     321 #
     322 sub GetFingerprintBitsAsRawBinaryString {
     323   my($This, $BitOrder) = @_;
     324
     325   return $This->_GetFingerprintBitsAsString('RawBinary', $BitOrder);
     326 }
     327
     328 # Get fingerprint bits as a string...
     329 #
     330 sub _GetFingerprintBitsAsString {
     331   my($This, $Format) = @_;
     332
     333   if (!$This->{FingerprintsBitVector}) {
     334     return undef;
     335   }
     336   FORMAT : {
     337     if ($Format =~ /^(Binary|Bin|BinaryString)$/i) { return $This->{FingerprintsBitVector}->GetBitsAsBinaryString(); last FORMAT; }
     338     if ($Format =~ /^(Hexadecimal|Hex|HexadecimalString)$/i) { return $This->{FingerprintsBitVector}->GetBitsAsHexadecimalString(); last FORMAT; }
     339     if ($Format =~ /^(RawBinary|RawBin|RawBinaryString)$/i) { return $This->{FingerprintsBitVector}->GetBitsAsRawBinaryString(); last FORMAT; }
     340     croak "Error: ${ClassName}->_GetFingerprintBitsAsString: Specified bit vector string format, $Format, is not supported. Value values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString, RawBinary, RawBin, RawBinaryString...";
     341   }
     342   return undef;
     343 }
     344
     345 #
     346 # Methods/functions for FingerprintsVector...
     347 #
     348
     349 # Initialize fingerprint vector...
     350 sub _InitializeFingerprintsVector {
     351   my($This) = @_;
     352
     353   if ($This->{VectorType} !~ /^FingerprintsVector$/i) {
     354     croak "Error: ${ClassName}->_InitializeFingerprintsVector: Can't initialize fingerprints vector: VectorType must be FingerprintsVector...";
     355   }
     356
     357   if ($This->{FingerprintsVectorType}) {
     358     $This->{FingerprintsVector} = new Fingerprints::FingerprintsVector('Type' => $This->{FingerprintsVectorType});
     359   }
     360   return $This;
     361 }
     362
     363 # Set FingerprintsVector object and make sure it's not already set...
     364 #
     365 sub SetFingerprintsVector {
     366   my($This, $FingerprintsVector) = @_;
     367
     368   if ($This->{FingerprintsVector}) {
     369     croak "Error: ${ClassName}->SetFingerprintsVector: Can't change FingerprintsVector object:  It's already set...";
     370   }
     371   $This->{FingerprintsVector} = $FingerprintsVector;
     372
     373   return $This;
     374 }
     375
     376 # Types of FingerprintsVector values: OrderedNumericalValues, NumericalValues or AlphaNumericalValues.
     377 #
     378 sub SetFingerprintsVectorType {
     379   my($This, $FingerprintsVectorType) = @_;
     380
     381   if ($This->{FingerprintsVectorType}) {
     382     croak "Error: ${ClassName}->SetFingerprintsVector: Can't change FingerprintsVectorType:  It's already set...";
     383   }
     384   if ($FingerprintsVectorType !~ /^(OrderedNumericalValues|NumericalValues|AlphaNumericalValues)$/i) {
     385     croak "Error: ${ClassName}->SetFingerprintsVectorType: Specified value, $FingerprintsVectorType, for Type is not vaild. Supported types in current release of MayaChemTools: OrderedNumericalValues, NumericalValues or AlphaNumericalValues";
     386   }
     387   $This->{FingerprintsVectorType} = $FingerprintsVectorType;
     388
     389   return $This;
     390 }
     391
     392 # Get fingerprints vector values as an array or reference to an array...
     393 #
     394 sub GetFingerprintsVectorValues {
     395   my($This) = @_;
     396
     397   if (!$This->{FingerprintsVector}) {
     398     return undef;
     399   }
     400   return $This->{FingerprintsVector}->GetValues();
     401 }
     402
     403 # Get fingerprints vector value IDs as an array or reference to an array...
     404 #
     405 sub GetFingerprintsVectorValueIDs {
     406   my($This) = @_;
     407
     408   if (!$This->{FingerprintsVector}) {
     409     return undef;
     410   }
     411   return $This->{FingerprintsVector}->GetValueIDs();
     412 }
     413