<jupyter_start><jupyter_text>Table of Contents 1&nbsp;&nbsp;setup2&nbsp;&nbsp;isIsomorphic code3&nbsp;&nbsp;compare time of original algorithm4&nbsp;&nbsp;compare time of new algorithm This notebook compares the efficiency of two methods to compare reaction isomorphism, to see the time benefits of it. Two similar H_abstraction reactions are created and compared to look at time efficiency.  setup<jupyter_code>from rmgpy.species import Species
from rmgpy.reaction import Reaction
from cProfile import run
r1 = Species().fromSMILES('C=CC=CC=CC=CC=C[CH2]')
r2 = Species().fromSMILES('C=CC=CC=CC=C[CH2]')
p1 = Species().fromSMILES('C=CC=CC=CC=CC')
p2a = Species().fromSMILES('C=CC=CC=CC=CC=C=C')
p2b = Species().fromSMILES('C=C=CC=CC=CC=C=CC')
species = [r1,r2,p1,p2a,p2b]
for s in species: s.generateResonanceIsomers()
rxn1 = Reaction(reactants=[r1,r2], products = [p1, p2a])
rxn2 = Reaction(reactants=[r1,r2], products = [p1, p2b])
rxn1copy = rxn1.copy()
rxn2swapped_reactants = Reaction(reactants=[r2,r1], products = [p2b, p1])<jupyter_output><empty_output><jupyter_text>isIsomorphic code<jupyter_code>def isIsomorphic(rxn1, other, eitherDirection=True, checkIdentical = False):
        """
        Return ``True`` if this reaction is the same as the `other` reaction,
        or ``False`` if they are different. The comparison involves comparing
        isomorphism of reactants and products, and doesn't use any kinetic
        information.

        If `eitherDirection=False` then the directions must match.
        """

        # Compare reactants to reactants
        forwardReactantsMatch = _isomorphicSpeciesList(rxn1.reactants, 
                                    other.reactants,checkIdentical = checkIdentical)
        
        # Compare products to products
        forwardProductsMatch = _isomorphicSpeciesList(rxn1.products, 
                                    other.products,checkIdentical = checkIdentical)

        # Return now, if we can
        if (forwardReactantsMatch and forwardProductsMatch):
            return True
        if not eitherDirection:
            return False
        
        # Compare reactants to products
        reverseReactantsMatch = _isomorphicSpeciesList(rxn1.reactants, 
                                    other.products,checkIdentical = checkIdentical)

        # Compare products to reactants
        reverseProductsMatch = _isomorphicSpeciesList(rxn1.products, 
                                    other.reactants,checkIdentical = checkIdentical)

        # should have already returned if it matches forwards, or we're not allowed to match backwards
        return  (reverseReactantsMatch and reverseProductsMatch)<jupyter_output><empty_output><jupyter_text>compare time of original algorithm<jupyter_code>def _isomorphicSpeciesList(list1, list2, checkIdentical=False):
    """
    This method compares whether lists of species or molecules are isomorphic
    or identical. It is used for the 'isIsomorphic' method of Reaction class.
    It likely can be useful elswehere as well:
        
        list1 - list of species/molecule objects of reaction1
        list2 - list of species/molecule objects of reaction2
        checkIdentical - if true, uses the 'isIdentical' comparison
                         if false, uses the 'isIsomorphic' comparison
                         
    Returns True if the lists are isomorphic/identical & false otherwise
    """

    def comparison_method(other1, other2, checkIdentical=checkIdentical):
        if checkIdentical:
            return other1.isIdentical(other2)
        else:
            return other1.isIsomorphic(other2)

    if len(list1) == len(list2) == 1:
        if comparison_method(list1[0], list2[0]):
            return True
    elif len(list1) == len(list2) == 2:
        if comparison_method(list1[0], list2[0]) \
                    and comparison_method(list1[1], list2[1]):
            return True
        elif comparison_method(list1[0], list2[1]) \
                    and comparison_method(list1[1], list2[0]):
            return True
    elif len(list1) == len(list2) == 3:
        if (    comparison_method(list1[0], list2[0]) and
                comparison_method(list1[1], list2[1]) and
                comparison_method(list1[2], list2[2]) ):
            return True
        elif (  comparison_method(list1[0], list2[0]) and
                comparison_method(list1[1], list2[2]) and
                comparison_method(list1[2], list2[1]) ):
            return True
        elif (  comparison_method(list1[0], list2[1]) and
                comparison_method(list1[1], list2[0]) and
                comparison_method(list1[2], list2[2]) ):
            return True
        elif (  comparison_method(list1[0], list2[2]) and
                comparison_method(list1[1], list2[0]) and
                comparison_method(list1[2], list2[1]) ):
            return True
        elif (  comparison_method(list1[0], list2[1]) and
                comparison_method(list1[1], list2[2]) and
                comparison_method(list1[2], list2[0]) ):
            return True
        elif (  comparison_method(list1[0], list2[2]) and
                comparison_method(list1[1], list2[1]) and
                comparison_method(list1[2], list2[0]) ):
            return True
    elif len(list1) == len(list2):
        raise NotImplementedError("Can't check isomorphism of lists with {0} species/molecules".format(len(list1)))
    # nothing found
    return False
run('for i in range(10000): isIsomorphic(rxn1,rxn2)',)
run('for i in range(10000): isIsomorphic(rxn1,rxn2swapped_reactants)')
run('for i in range(10000): isIsomorphic(rxn1,rxn1copy)')<jupyter_output>150003 function calls in 0.970 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    10000    0.011    0.000    0.965    0.000 <ipython-input-40-95d0327e9f94>:1(isIsomorphic)
    20000    0.031    0.000    0.954    0.000 <ipython-input-41-d3da26f90ae7>:1(_isomorphicSpeciesList)
    40000    0.919    0.000    0.919    0.000 <ipython-input-41-d3da26f90ae7>:15(comparison_method)
        1    0.005    0.005    0.970    0.970 <string>:1(<module>)
    80000    0.004    0.000    0.004    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {range}<jupyter_text>compare time of new algorithm<jupyter_code>def _isomorphicSpeciesList(list1, list2, checkIdentical=False):
    """
    This method compares whether lists of species or molecules are isomorphic
    or identical. It is used for the 'isIsomorphic' method of Reaction class.
    It likely can be useful elswehere as well:
        
        list1 - list of species/molecule objects of reaction1
        list2 - list of species/molecule objects of reaction2
        checkIdentical - if true, uses the 'isIdentical' comparison
                         if false, uses the 'isIsomorphic' comparison
                         
    Returns True if the lists are isomorphic/identical & false otherwise
    """

    def comparison_method(other1, other2, checkIdentical=checkIdentical):
        if checkIdentical:
            return other1.isIdentical(other2)
        else:
            return other1.isIsomorphic(other2)

    list2Temp = list2[:]
    for entry in list1:
       for index, entry2 in enumerate(list2Temp):
           if comparison_method(entry,entry2):
               del list2Temp[index]
               break
       else: #loop doesn't break, something is missing
             return False
    #all loops completed
    return True
run('for i in range(10000): isIsomorphic(rxn1,rxn2)',)
run('for i in range(10000): isIsomorphic(rxn1,rxn2swapped_reactants)')
run('for i in range(10000): isIsomorphic(rxn1,rxn1copy)')<jupyter_output>70003 function calls in 1.005 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    10000    0.012    0.000    0.999    0.000 <ipython-input-40-95d0327e9f94>:1(isIsomorphic)
    20000    0.048    0.000    0.988    0.000 <ipython-input-45-2de5dad1ee6b>:1(_isomorphicSpeciesList)
    40000    0.940    0.000    0.940    0.000 <ipython-input-45-2de5dad1ee6b>:15(comparison_method)
        1    0.005    0.005    1.005    1.005 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {range}
{'fraction_non_alphanumeric': 0.09410792301334278, 'fraction_numerical': 0.06423426614712481, 'mean_word_length': 2.6714347637624623, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '540908', 'license': 'MIT', 'n_tokens_mistral': 2855, 'n_tokens_neox': 2575, 'n_words': 665, 'path': 'issues/profile efficiency of reaction isomorphic checking.ipynb', 'repo_name': 'goldmanm/rmg_walkthroughs', 'size': '8469'}