       1 package Fingerprints::FingerprintsStringUtil;
       2 #
       3 # File: FingerprintsStringUtil.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 Exporter;
      28 use Carp;
      29 use TextUtil ();
      30 use Fingerprints::FingerprintsBitVector;
      31 use Fingerprints::FingerprintsVector;
      32
      33 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
      34
      35 @ISA = qw(Exporter);
      36 @EXPORT = qw();
      37 @EXPORT_OK = qw(AreFingerprintsStringValuesValid GenerateFingerprintsString GenerateFingerprintsBitVectorString GenerateFingerprintsVectorString GetFingerprintsStringTypeAndDescription GetDefaultBitsOrder GetDefaultBitStringFormat GetDefaultVectorStringFormat GetFingeprintsStringDelimiter GetFingerprintsStringValues ParseFingerprintsString ParseFingerprintsBitVectorString ParseFingerprintsVectorString);
      38
      39 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
      40
      41 # Fingerprint string values delimiter...
      42 my($FPStringDelim) = ';';
      43
      44 # Generate fingerprints string...
      45 #
      46 sub GenerateFingerprintsString {
      47   my($FingerprintsObject) = @_;
      48   my($VectorType);
      49
      50   $VectorType = $FingerprintsObject->GetVectorType();
      51
      52   VECTORTYPE : {
      53     if ($VectorType =~ /^FingerprintsBitVector$/i) { return GenerateFingerprintsBitVectorString(@_); last VECTORTYPE; }
      54     if ($VectorType =~ /^FingerprintsVector$/i) { return GenerateFingerprintsVectorString(@_); last VECTORTYPE; }
      55     croak "Error: FingerprintsStringUtil::GenerateFingerprintsString: Fingerprints object vector type, $VectorType, is not supported. Valid values: FingerprintsBitVector or FingerprintsVector...";
      56   }
      57   return '';
      58 }
      59
      60 # Generate fingerprints bit vector string...
      61 #
      62 sub GenerateFingerprintsBitVectorString {
      63   my($FingerprintsObject, $BitStringFormat, $BitsOrder) = @_;
      64   my($FingerprintsString, $FingerprintsBitVector, @FingerprintsStringValues);
      65
      66   if (!$BitStringFormat) { $BitStringFormat = GetDefaultBitStringFormat(); }
      67   if (!$BitsOrder) {$BitsOrder = GetDefaultBitsOrder(); }
      68
      69   $FingerprintsString = '';
      70   $FingerprintsBitVector = Fingerprints::FingerprintsBitVector::IsFingerprintsBitVector($FingerprintsObject) ? $FingerprintsObject : $FingerprintsObject->GetFingerprintsBitVector();
      71
      72   # Use specified size instead of size: it corresponds to actual size of the fingerprints bit vector;
      73   # size reflects actual internal size including any padding.
      74   #
      75
      76   @FingerprintsStringValues = ();
      77   push @FingerprintsStringValues, ($FingerprintsObject->GetVectorType(), _GetFingerprintsDescription($FingerprintsObject), $FingerprintsBitVector->GetSpecifiedSize(), $BitStringFormat, $BitsOrder);
      78
      79   $FingerprintsString = join("${FPStringDelim}",  @FingerprintsStringValues) . "${FPStringDelim}" . _GetFingerprintBitVectorString($FingerprintsBitVector, $BitStringFormat, $BitsOrder);
      80
      81   return $FingerprintsString;
      82 }
      83
      84 # Get fingerprint bit vector string...
      85 #
      86 sub _GetFingerprintBitVectorString {
      87   my($FingerprintsBitVector, $BitStringFormat, $BitsOrder) = @_;
      88   my($FingerprintBitString);
      89
      90   if (!$BitStringFormat) { $BitStringFormat = GetDefaultBitStringFormat(); }
      91   if (!$BitsOrder) {$BitsOrder = GetDefaultBitsOrder(); }
      92
      93   $FingerprintBitString = '';
      94   if (!$FingerprintsBitVector) {return $FingerprintBitString;}
      95
      96   BITSTRINGFORMAT : {
      97     if ($BitStringFormat =~ /^(BinaryString|Binary|Bin)$/i) { return $FingerprintsBitVector->GetBitsAsBinaryString($BitsOrder); last BITSTRINGFORMAT; }
      98     if ($BitStringFormat =~ /^(HexadecimalString|Hexadecimal|Hex)$/i) { return $FingerprintsBitVector->GetBitsAsHexadecimalString($BitsOrder); last BITSTRINGFORMAT; }
      99     croak "Error: FingerprintsStringUtil::_GetFingerprintBitsAsString: Specified bit vector string format, $BitStringFormat, is not supported. Value values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString...";
     100   }
     101   return $FingerprintBitString;
     102 }
     103
     104 # Generate fingerprints vector string...
     105 #
     106 sub GenerateFingerprintsVectorString {
     107   my($FingerprintsObject, $VectorStringFormat) = @_;
     108   my($FingerprintsString, $FingerprintsVector, @FingerprintsStringValues);
     109
     110   $FingerprintsString = '';
     111   $FingerprintsVector = Fingerprints::FingerprintsVector::IsFingerprintsVector($FingerprintsObject) ? $FingerprintsObject : $FingerprintsObject->GetFingerprintsVector();
     112
     113   if (!$VectorStringFormat) { $VectorStringFormat = _GetDefaultVectorStringFormat($FingerprintsVector); }
     114
     115   @FingerprintsStringValues = ();
     116   push @FingerprintsStringValues, ($FingerprintsObject->GetVectorType(), _GetFingerprintsDescription($FingerprintsObject), $FingerprintsVector->GetNumOfValues(), $FingerprintsVector->GetType(), $VectorStringFormat);
     117
     118   $FingerprintsString = join("${FPStringDelim}",  @FingerprintsStringValues) . "${FPStringDelim}" . _GetFingerprintVectorString($FingerprintsVector, $VectorStringFormat);
     119
     120   return $FingerprintsString;
     121 }
     122
     123 # Get fingerprint vector string...
     124 #
     125 sub _GetFingerprintVectorString {
     126   my($FingerprintsVector, $VectorStringFormat) = @_;
     127   my($FingerprintString);
     128
     129   if (!$VectorStringFormat) { $VectorStringFormat = _GetDefaultVectorStringFormat($FingerprintsVector);}
     130
     131   $FingerprintString = '';
     132   if (!$FingerprintsVector) {return $FingerprintString;}
     133
     134   VECTORSTRINGFORMAT : {
     135     if ($VectorStringFormat =~ /^(IDsAndValuesString|IDsAndValues)$/i) { return $FingerprintsVector->GetIDsAndValuesString(); last VECTORSTRINGFORMAT; }
     136     if ($VectorStringFormat =~ /^(IDsAndValuesPairsString|IDsAndValuesPairs)$/i) { return $FingerprintsVector->GetIDsAndValuesPairsString(); last VECTORSTRINGFORMAT; }
     137     if ($VectorStringFormat =~ /^(ValuesAndIDsString|ValuesAndIDs)$/i) { return $FingerprintsVector->GetValuesAndIDsString(); last VECTORSTRINGFORMAT; }
     138     if ($VectorStringFormat =~ /^(ValuesAndIDsPairsString|ValuesAndIDsPairs)$/i) { return $FingerprintsVector->GetValuesAndIDsPairsString(); last VECTORSTRINGFORMAT; }
     139     if ($VectorStringFormat =~ /^(ValuesString|Values)$/i) { return $FingerprintsVector->GetValuesString(); last VECTORSTRINGFORMAT; }
     140     croak "Error: FingerprintsStringUtil::_GetFingerprintVectorString: Specified vector string format, $VectorStringFormat, is not supported. Value values: IDsAndValuesString, IDsAndValues, IDsAndValuesPairsString, IDsAndValuesPairs, ValuesAndIDsString, ValuesAndIDs, ValuesAndIDsPairsString, ValuesAndIDsPairs, ValuesString, Values...";
     141   }
     142   return $FingerprintString;
     143 }
     144
     145 # Get fingerprints string type and description...
     146 sub GetFingerprintsStringTypeAndDescription {
     147   my($FingerprintsString) = @_;
     148   my($Type, $Description);
     149
     150   ($Type, $Description) = _ParseFingerprintsStringValues($FingerprintsString);
     151
     152   return ($Type, $Description);
     153 }
     154
     155 # Get all fingerprints string values...
     156 sub GetFingerprintsStringValues {
     157   my($FingerprintsString) = @_;
     158
     159   return _ParseFingerprintsStringValues($FingerprintsString);
     160 }
     161
     162 # Parse fingerprints string and return FingerprintsBitVector or FingerprintsVector object...
     163 #
     164 sub ParseFingerprintsString {
     165   my($FingerprintsString) = @_;
     166
     167   VECTORTYPE : {
     168     if ($FingerprintsString =~ /^FingerprintsBitVector/i) { return ParseFingerprintsBitVectorString(@_); last VECTORTYPE; }
     169     if ($FingerprintsString =~ /^FingerprintsVector/i) { return ParseFingerprintsVectorString(@_); last VECTORTYPE; }
     170     croak "Error: FingerprintsStringUtil::ParseFingerprintsString: Fingerprints string vector type is not supported. Valid values: FingerprintsBitVector or FingerprintsVector...";
     171   }
     172   return undef;
     173 }
     174
     175 # Parse fingerprints bit vector string and retrun bit vector...
     176 #
     177 sub ParseFingerprintsBitVectorString {
     178   my($FingerprintsString, $ValidateValues) = @_;
     179   my($ErrorMsgPrefix, $VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString);
     180
     181   $ErrorMsgPrefix = "Error: ParsePathLengthFingerprintsBitVectorString";
     182   ($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString) = _ParseFingerprintsStringValues($FingerprintsString);
     183   if ($ValidateValues) {
     184     _ValidateFingerprintsStringValues($ErrorMsgPrefix, $VectorType, $Size, $BitStringFormat, $BitsOrder, $BitVectorString);
     185   }
     186
     187   return _GenerateFingerprintBitVector($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString);
     188 }
     189
     190 # Generate fingerints bit vector...
     191 #
     192 sub _GenerateFingerprintBitVector {
     193   my($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString) = @_;
     194   my($FingerprintsBitVector);
     195
     196   $FingerprintsBitVector = undef;
     197
     198   BITSTRINGFORMAT : {
     199     if ($BitStringFormat =~ /^(BinaryString|Binary|Bin)$/i) {
     200       $FingerprintsBitVector = Fingerprints::FingerprintsBitVector::NewFromBinaryString($BitVectorString, $BitsOrder);
     201       last BITSTRINGFORMAT;
     202     }
     203     if ($BitStringFormat =~ /^(HexadecimalString|Hexadecimal|Hex)$/i) {
     204       $FingerprintsBitVector = Fingerprints::FingerprintsBitVector::NewFromHexadecimalString($BitVectorString, $BitsOrder);
     205       last BITSTRINGFORMAT;
     206     }
     207     croak "Error: FingerprintsStringUtil::_GenerateFingerprintBitVector: Specified bit vector string format, $BitStringFormat, is not supported. Value values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString...";
     208   }
     209
     210   if (defined $FingerprintsBitVector) {
     211     # Set fingerints vector type and description...
     212     $FingerprintsBitVector->SetVectorType($VectorType);
     213     $FingerprintsBitVector->SetDescription($Description);
     214
     215     # Set specified size which might be different from the bit string size due to padding
     216     # used by Perl vec function to handle bit vectors in BitVectot class...
     217     #
     218     $FingerprintsBitVector->SetSpecifiedSize($Size);
     219   }
     220
     221   return $FingerprintsBitVector;
     222 }
     223
     224 # Parse fingerprints vector string and retrun vector...
     225 #
     226 sub ParseFingerprintsVectorString {
     227   my($FingerprintsString, $ValidateValues) = @_;
     228   my($ErrorMsgPrefix, $VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2);
     229
     230   $ErrorMsgPrefix = "Error: ParseFingerprintsVectorString";
     231   ($VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2) = _ParseFingerprintsStringValues($FingerprintsString);
     232
     233   # No need to check $VectorString1 and $VectorString2 values as they would be
     234   # checked later during the creation of FingerprintsVector...
     235   #
     236   if ($ValidateValues) {
     237     _ValidateFingerprintsStringValues($ErrorMsgPrefix, $VectorType, $NumOfValues, $VectorValuesType, $VectorStringFormat);
     238   }
     239
     240   return _GenerateFingerprintVector($VectorType, $Description, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2);
     241 }
     242
     243 # Generate fingerints vector...
     244 #
     245 sub _GenerateFingerprintVector {
     246   my($VectorType, $Description, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2) = @_;
     247   my($FingerprintsVector, $VectorString);
     248
     249   $VectorString = TextUtil::IsEmpty($VectorString2) ? $VectorString1 : "${VectorString1};${VectorString2}";
     250   $FingerprintsVector = undef;
     251
     252   VECTORSTRINGFORMAT : {
     253     if ($VectorStringFormat =~ /^(ValuesString|Values)$/i) {
     254       $FingerprintsVector = Fingerprints::FingerprintsVector::NewFromValuesString($VectorValuesType, $VectorString);
     255       last VECTORSTRINGFORMAT;
     256     }
     257     if ($VectorStringFormat =~ /^(IDsAndValuesString|IDsAndValues)$/i) {
     258       $FingerprintsVector = Fingerprints::FingerprintsVector::NewFromIDsAndValuesString($VectorValuesType, $VectorString);
     259       last VECTORSTRINGFORMAT;
     260     }
     261     if ($VectorStringFormat =~ /^(IDsAndValuesPairsString|IDsAndValuesPairs)$/i) {
     262       $FingerprintsVector = Fingerprints::FingerprintsVector::NewFromIDsAndValuesPairsString($VectorValuesType, $VectorString);
     263       last VECTORSTRINGFORMAT;
     264     }
     265     if ($VectorStringFormat =~ /^(ValuesAndIDsString|ValuesAndIDs)$/i) {
     266       $FingerprintsVector = Fingerprints::FingerprintsVector::NewFromValuesAndIDsString($VectorValuesType, $VectorString);
     267       last VECTORSTRINGFORMAT;
     268     }
     269     if ($VectorStringFormat =~ /^(ValuesAndIDsPairsString|ValuesAndIDsPairs)$/i) {
     270       $FingerprintsVector = Fingerprints::FingerprintsVector::NewFromValuesAndIDsPairsString($VectorValuesType, $VectorString);
     271       last VECTORSTRINGFORMAT;
     272     }
     273     croak "Error: FingerprintsStringUtil::_GenerateFingerprintVector: Specified vector string format, $VectorStringFormat, is not supported. Value values: IDsAndValuesString, IDsAndValues, IDsAndValuesPairsString, IDsAndValuesPairs, ValuesAndIDsString, ValuesAndIDs, ValuesAndIDsPairsString, ValuesAndIDsPairs, ValuesString, Values...";
     274   }
     275
     276   if (defined $FingerprintsVector) {
     277     # Set fingerints vector type and description...
     278     $FingerprintsVector->SetVectorType($VectorType);
     279     $FingerprintsVector->SetDescription($Description);
     280   }
     281
     282   return $FingerprintsVector;
     283 }
     284
     285 # Validate fingerint string values...
     286 #
     287 sub AreFingerprintsStringValuesValid {
     288   my($FingerprintsString) = @_;
     289   my($Value);
     290
     291   for $Value (_ParseFingerprintsStringValues($FingerprintsString)) {
     292     if (TextUtil::IsEmpty($Value)) {
     293       return 0;
     294     }
     295   }
     296   return 1;
     297 }
     298
     299 # Get fingerprints description...
     300 #
     301 sub _GetFingerprintsDescription {
     302   my($FingerprintsObject) = @_;
     303   my($Description);
     304
     305   $Description = $FingerprintsObject->GetDescription();
     306
     307   return TextUtil::IsEmpty($Description) ? 'No description available for fingerprints' : $Description;
     308 }
     309
     310 # Parse fingerprints string values...
     311 #
     312 sub _ParseFingerprintsStringValues {
     313   my($FingerprintsString) = @_;
     314
     315   return split "${FPStringDelim}", $FingerprintsString;
     316 }
     317
     318 # Check to make sure already parsed fingerprints string values are valid....
     319 #
     320 sub _ValidateFingerprintsStringValues {
     321   my($ErrorMsgPrefix, @Values) = @_;
     322   my($Value);
     323
     324   for $Value (@Values) {
     325     if (TextUtil::IsEmpty($Value)) {
     326       croak("${ErrorMsgPrefix}: _ValidateFingerprintsStringValues: Fingerprints string format is not valid: An empty value found...");
     327     }
     328   }
     329 }
     330
     331 # Default bit string format...
     332 #
     333 sub GetDefaultBitStringFormat {
     334   return 'HexadecimalString';
     335 }
     336
     337 # Default bit order...
     338 #
     339 sub GetDefaultBitsOrder {
     340   return 'Ascending';
     341 }
     342
     343 # Default vector string format using fingerprints or fingerprints vector object...
     344 #
     345 sub GetDefaultVectorStringFormat {
     346   my($FingerprintsObject) = @_;
     347   my($FingerprintsVector);
     348
     349   $FingerprintsVector = Fingerprints::FingerprintsVector::IsFingerprintsVector($FingerprintsObject) ? $FingerprintsObject : $FingerprintsObject->GetFingerprintsVector();
     350
     351   return _GetDefaultVectorStringFormat($FingerprintsVector);
     352 }
     353
     354 # Default vector string format using fingerprits vector object...
     355 #
     356 sub _GetDefaultVectorStringFormat {
     357   my($FingerprintsVector) = @_;
     358   my($Type);
     359
     360   $Type = $FingerprintsVector->GetType();
     361
     362   return ($Type =~ /^NumericalValues$/i) ? 'IDsAndValuesString' : 'ValuesString';
     363 }
     364
     365 # Fingerprints string delimiter...
     366 #
     367 sub GetFingeprintsStringDelimiter {
     368   return $FPStringDelim;
     369 }
     370