MayaChemTools

   1 package Fingerprints::Fingerprints;
   2 #
   3 # File: Fingerprints.pm
   4 # Author: Manish Sud <msud@san.rr.com>
   5 #
   6 # Copyright (C) 2024 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