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