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