I think it should be deduplication identical paths 4_C_O vs 4_O_C are the same but both get captured but then also double counted!
If you do that you get the following for your molecule. hash: 236 2 4_C_O hash: 156 6 3_C_C hash: 78 12 2_C_C hash: 0 12 1_C_C hash: 80 4 2_C_O hash: 2 2 1_C_O hash: 158 4 3_C_O The hash being a bit id also isn't ideal. Anyways it's broken in multiple ways, is an atom pair fingerprint that important? I'm wonder if we just deprecate/delete it. Best, John On Fri, 25 Sept 2026 at 16:10, John Mayfield <[email protected]> wrote: > Just had a quick look, yeah it's (very) broken :-). > > The issue is there is a "fixed" set of features that it wants to capture > for binary but count mode gets *all* the features. > > So the fix is either the count fingerprint should only report the > "selected features" or it should hash the path directly. I'll have a bit > more a think but and may need to check the original PaDEL implementation. > > Best, > John > > On Wed, 23 Sept 2026 at 10:25, Andrew Dalke <[email protected]> > wrote: > >> Hi everyone, >> >> I'm confused about how to get the count information from the >> AtomPairs2D fingerprint in CDK and wondered if anyone here could help. >> >> Once I get the fingerprint, how do I get the feature index and associated >> count? >> >> When I try it out with my test case, below, I find there are 11 populated >> bins but I can only pull out 7 hashes (the other indices raise an >> exception), while I can get all 11 counts. >> >> I don't know if this is an error in the CDK implementation, or I simply >> don't know how to get the data. >> >> Assuming the code is working correctly, my two ideas for how to map hash >> to count are: >> >> 1) use fp.getHash(i), fp.getCount(i) when fp.getHash(i) does not throw >> an exception >> >> (I think this is the correct one as fp.getCount(i) matches >> fp.getCountForHash(fp.getHash(i))) >> >> 2) use fp.getHash(i), fp.getCount(j) where j is the j^th fp.getHash(i) >> which does not throw an exception >> >> >> Here is my reproducible, which is in Python accessing cdk-2.13.jar via >> the JPype Java/Python bridge, which I set up in my chemfp package for >> working with cheminformatics fingerprints. >> >> ==== >> # This does the work to initialize the Java/Python bridge >> from chemfp import cdk_types >> >> from org.openscience import cdk >> from org.openscience.cdk.fingerprint import AtomPairs2DFingerprinter >> >> fingerprinter = AtomPairs2DFingerprinter() >> # prints: >> # fingerprinter.getSize()=780 >> print(f"{fingerprinter.getSize()=}") >> >> from org.openscience.cdk.smiles import SmilesParser >> parser = SmilesParser(cdk.silent.SilentChemObjectBuilder.getInstance()) >> mol = parser.parseSmiles("c1ccccc1O") >> >> fp = fingerprinter.getCountFingerprint(mol) >> # prints: >> # fp.size()=780 >> print(f"{fp.size()=}") >> >> # prints: >> # fp.numOfPopulatedbins()=11 >> print(f"{fp.numOfPopulatedbins()=}") >> >> # I expected to get the feature indices as getHash(i) for 0 <= i < 11, >> # but if I do that manually I get failures for getHash(2) and a few others >> >> # >>> fp.getHash(0) >> # 236 >> # >>> fp.getHash(1) >> # 156 >> # >>> fp.getHash(2) >> # Traceback (most recent call last): >> # File "AtomPairs2DFingerprinter.java", line 216, in >> org.openscience.cdk.fingerprint.AtomPairs2DFingerprinter$1.getHash >> # Exception: Java Exception >> # >> # The above exception was the direct cause of the following exception: >> # >> # Traceback (most recent call last): >> # File "<stdin>", line 1, in <module> >> # java.lang.java.lang.NullPointerException: >> java.lang.NullPointerException: Cannot invoke >> "java.lang.Integer.intValue()" because the return value of >> "java.util.Map.get(Object)" is null >> >> # Instead, I'll scan all of the indices 0 <= i < 780 and get >> # the sparse index of (i, value) for both the hashes and counts >> >> def get_hashes_and_counts(fp): >> hashes = [] >> counts = [] >> for i in range(780): >> try: >> hashes.append((i, fp.getHash(i))) >> except Exception: >> pass >> try: >> counts.append((i, fp.getCount(i))) >> except Exception: >> pass >> >> return hashes, counts >> >> hashes, counts = get_hashes_and_counts(fp) >> >> # prints: >> # hashes=[(0, 236), (1, 156), (3, 78), (4, 0), (5, 80), >> # (7, 2), (10, 158)] >> print(f"{hashes=}") >> >> # prints: >> # counts=[(0, 1), (1, 6), (2, 1), (3, 12), (4, 12), (5, 2), >> # (6, 2), (7, 1), (8, 1), (9, 2), (10, 2)] >> print(f"{counts=}") >> >> # I can see three interpretations: >> >> ## == Option 1 == >> # use (fp.GetHash(i), fp.GetCount(i) if GetHash(i) is valid >> >> def get_sparse_features1(fp): >> features = [] >> for i in range(fp.numOfPopulatedbins()): >> try: >> feature_idx = fp.getHash(i) >> except Exception: >> continue >> # Or use fp.getCountForHash(feature_idx) >> features.append((feature_idx, fp.getCount(i))) >> return features >> >> # prints: >> # get_sparse_features1(fp)=[(236, 1), (156, 6), (78, 12), (0, 12), >> # (80, 2), (2, 1), (158, 2)] >> print(f"{get_sparse_features1(fp)=}") >> >> ## == Option 2 == >> # use (fp.GetHash(i), fp.GetCount(j) for the j-th valid GetHash(i) >> >> def get_sparse_features2(fp): >> features = [] >> j = 0 >> for i in range(fp.numOfPopulatedbins()): >> try: >> feature_idx = fp.getHash(i) >> except Exception: >> continue >> features.append((feature_idx, fp.getCount(j))) >> j += 1 >> return features >> >> # prints: >> # get_sparse_features2(fp)=[(236, 1), (156, 6), (78, 1), (0, 12), >> # (80, 12), (2, 2), (158, 2)] >> print(f"{get_sparse_features2(fp)=}") >> >> # (These give different counts than option 1, because of the >> # different way of using getCount) >> >> ## == Option 3 == >> # Something is wrong with the implementation >> >> def get_sparse_features3(fp): >> raise NotImplementedError("It is not possible to get the count >> features") >> >> >> Andrew >> [email protected] >> >> >> >> >> >> _______________________________________________ >> Cdk-user mailing list >> [email protected] >> https://lists.sourceforge.net/lists/listinfo/cdk-user >> >
_______________________________________________ Cdk-user mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/cdk-user

