def test_self_displacement_03(self):
        complexes, reactions = read_pil("""
        length x1 = 10
        length x2 = 10
        length y1 = 10
        length y2 = 10
        B1 = x1( x2( y1( y2( x1( x2( y1 y2 x1 x2 + ) ) ) ) ) )
        B2 = x1 x2 y1 y2 x1( x2( y1( y2( x1( x2( + ) ) ) ) ) )
        i1 = x1( x2( y1 y2 x1 x2 y1( y2( x1( x2( + ) ) ) ) ) )
        i2 = x1( x2( y1( y2( x1 x2 y1 y2 x1( x2( + ) ) ) ) ) )
        """)
        B1 = complexes['B1']
        B2 = complexes['B2']
        i1 = complexes['i1']
        i2 = complexes['i2']
        path1 = PepperReaction([B1], [i1], 'branch-3way')
        path1r = PepperReaction([i1], [B1], 'branch-3way')
        path1f = PepperReaction([i1], [B2], 'branch-3way')
        path2 = PepperReaction([B2], [i2], 'branch-3way')
        path2r = PepperReaction([i2], [B2], 'branch-3way')
        path2f = PepperReaction([i2], [B1], 'branch-3way')

        enum = Enumerator([B1])
        enum.max_helix = True
        enum.enumerate()
        self.assertEqual(
            sorted(enum.reactions),
            sorted([path1, path1r, path1f, path2, path2r, path2f]))
    def test_self_displacement_01(self):
        complexes, reactions = read_pil("""
        length x = 10
        length y = 10
        B1 = x( y( x( y x + ) ) )
        B2 = x y x( y( x( + ) ) )
        B3 = x( y( x y x( + ) ) )
        B4 = x( y x y( x( + ) ) )
        """)
        B1 = complexes['B1']
        B2 = complexes['B2']
        B3 = complexes['B3']
        B4 = complexes['B4']
        path1 = PepperReaction([B1], [B4], 'branch-3way')
        path1r = PepperReaction([B4], [B1], 'branch-3way')
        path2 = PepperReaction([B4], [B2], 'branch-3way')
        path3 = PepperReaction([B2], [B3], 'branch-3way')
        path3r = PepperReaction([B3], [B2], 'branch-3way')
        path4 = PepperReaction([B3], [B1], 'branch-3way')

        enum = Enumerator([B1])
        enum.max_helix = True
        enum.enumerate()
        self.assertEqual(sorted(enum.reactions),
                         sorted([path1, path1r, path2, path3, path3r, path4]))
    def test_self_displacement_02(self):
        complexes, reactions = read_pil("""
        length x = 10
        length y = 10
        T = x( y x + ) y* x*
        T1 = x( y x + x* y* )
        T2 = x y x( + ) y* x*
        T3 = x( y( x( + ) ) )
        T4 = x y x( + x* y* )
        """)
        T = complexes['T']
        T1 = complexes['T1']
        T2 = complexes['T2']
        T3 = complexes['T3']
        T4 = complexes['T4']
        path1 = PepperReaction([T], [T1], 'branch-3way')
        path1r = PepperReaction([T1], [T], 'branch-3way')
        path2 = PepperReaction([T], [T2], 'branch-3way')
        path2r = PepperReaction([T2], [T], 'branch-3way')
        path3 = PepperReaction([T1], [T3], 'bind11')
        path4 = PepperReaction([T2], [T3], 'bind11')
        path5 = PepperReaction([T1], [T4], 'branch-3way')
        path5r = PepperReaction([T4], [T1], 'branch-3way')
        path6 = PepperReaction([T2], [T4], 'branch-3way')
        path6r = PepperReaction([T4], [T2], 'branch-3way')

        enum = Enumerator([T])
        enum.max_helix = True
        enum.enumerate()
        self.assertEqual(
            sorted(enum.reactions),
            sorted([
                path1, path1r, path2, path2r, path3, path4, path5, path5r,
                path6, path6r
            ]))
    def test_CondenseGraphCRN_01(self):
        complexes = self.complexes
        reactions = self.reactions
        cplx = self.cplx
        rxn = self.rxn
        rs = self.rs

        rxn('A -> B + C')
        rxn('B -> D + E', k=0.5)
        rxn('C -> F + G', k=1)
        #rxn('B + C -> A') # raises error

        enum = Enumerator(complexes.values(), list(reactions))
        enum.dry_run()
        #for r in enum.reactions: print r, r.rate
        #print enum.complexes

        enumRG = PepperCondensation(enum)
        enumRG.condense()
        self.assertEqual(enumRG.condensed_reactions, [])
        self.assertEqual(
            enumRG.resting_sets,
            [rs('E'), rs('D'), rs('F'), rs('G')])
        self.assertEqual(enumRG.get_fates(cplx('A')),
                         SetOfFates([[rs('E'),
                                      rs('D'),
                                      rs('F'),
                                      rs('G')]]))
    def test_CondenseGraphCRN_02(self):
        complexes = self.complexes
        reactions = self.reactions
        cplx = self.cplx
        rxn = self.rxn
        rs = self.rs

        rxn('A -> B')
        rxn('A -> C')
        rxn('B -> D')
        rxn('B -> E')
        rxn('C -> F')
        rxn('C -> G')

        enum = Enumerator(complexes.values(), list(reactions))
        enum.dry_run()

        enumRG = PepperCondensation(enum)
        enumRG.condense()
        self.assertEqual(
            enumRG.resting_sets,
            [rs('E'), rs('D'), rs('F'), rs('G')])
        self.assertEqual(
            enumRG.get_fates(cplx('A')),
            SetOfFates([[rs('E')], [rs('D')], [rs('F')], [rs('G')]]))
        self.assertEqual(enumRG.get_fates(cplx('C')),
                         SetOfFates([[rs('F')], [rs('G')]]))
        self.assertEqual(enumRG.get_fates(cplx('F')), SetOfFates([[rs('F')]]))
    def test_CondenseGraphCRN_03(self):
        complexes = self.complexes
        reactions = self.reactions
        cplx = self.cplx
        rxn = self.rxn
        rs = self.rs

        rxn('X -> T1', k=0.1)
        rxn('T1 -> T2')
        rxn('T2 -> T1')
        rxn('T1 -> A')
        rxn('T1 -> B')
        rxn('T2 -> T3')
        rxn('T3 -> D')
        rxn('T3 -> C')

        enum = Enumerator(complexes.values(), list(reactions))
        enum.k_fast = 0.5
        enum.dry_run()

        enumRG = PepperCondensation(enum)
        enumRG.condense()

        self.assertEqual(sorted(enumRG.resting_sets),
                         sorted([rs('X'),
                                 rs('A'),
                                 rs('B'),
                                 rs('C'),
                                 rs('D')]))

        self.assertEqual(enumRG.get_fates(cplx('X')), SetOfFates([[rs('X')]]))

        self.assertEqual(
            enumRG.get_fates(cplx('T1')),
            SetOfFates([[rs('A')], [rs('B')], [rs('C')], [rs('D')]]))
    def test_bind_and_displace3way(self):
        complexes, reactions = read_pil("""
        length a = 10
        length b = 10
        length c = 10
        length t = 5

        I = a b c
        J = b c
        C = b( c( + ) ) a*
        B = a( b c + b( c( + ) ) )
        D = a( b( c( + ) ) )
        """)
        I = complexes['I']
        J = complexes['J']
        C = complexes['C']
        B = complexes['B']
        D = complexes['D']

        # DSD-pathway "bind21"
        path1 = PepperReaction([I, C], [B], 'bind21')
        # DSD-pathway "branch3way"
        path2 = PepperReaction([B], [D, J], 'branch-3way')

        enum = Enumerator(list(complexes.values()))
        enum.enumerate()
        self.assertEqual(sorted(enum.reactions), sorted([path1, path2]))
Example #8
0
  def test_peppercorn_interface(self):
    """ Make sure peppercorn.utils did not change """

    t0  = peputils.Domain('t0', 5, sequence='H'*5)
    t0_ = peputils.Domain('t0', 5, sequence='D'*5, is_complement=True)
    d1  = peputils.Domain('d1', 15, sequence='H'*15)
    d1_ = peputils.Domain('d1', 15, sequence='D'*15, is_complement=True)
    domains = [t0,t0_,d1,d1_]

    s0  = peputils.Strand('s0', [t0, d1])
    s1  = peputils.Strand('s1', [d1])
    s2  = peputils.Strand('s2', [d1_, t0_])
    strands = [s0,s1,s2]

    c1s = peputils.parse_dot_paren('..')
    c1  = peputils.Complex('c1', [s0], c1s)
    c1.check_structure()

    c2s = peputils.parse_dot_paren('(+).')
    c2  = peputils.Complex('c2', [s1,s2], c2s)
    c2.check_structure()
    complexes = [c1,c2]

    enum = Enumerator(domains, strands, complexes)

    enum.enumerate()

    ###########################
    # Get full output CRN
    reactions = enum.reactions

    self.assertEqual(len(reactions), 3)

    r1_kernel = 't0 d1  +  d1( + ) t0*  ->  t0( d1 + d1( + ) )'
    r2_kernel = 't0( d1 + d1( + ) )  ->  t0( d1( + ) )  +  d1'
    r3_kernel = 't0( d1 + d1( + ) )  ->  t0 d1  +  d1( + ) t0*'

    p_cntr = Counter()
    r_cntr = Counter()
    for r in sorted(reactions):
      #print r.kernel_string()
      for cx in r.reactants :
        p_cntr += Counter(map(str, cx.strands))
      for cx in r.products:
        r_cntr += Counter(map(str, cx.strands))

      self.assertEqual(p_cntr, r_cntr)
      self.assertTrue(r.kernel_string() in [r1_kernel, r2_kernel, r3_kernel])

    ###########################
    # Get condensed output CRN
    condensed = condense_resting_states(enum, compute_rates=True, k_fast = 0.)
    reactions = condensed['reactions']

    self.assertEqual(len(reactions), 1)

    result_kernel = 't0 d1  +  d1( + ) t0*  ->  t0( d1( + ) )  +  d1'
    self.assertEqual(reactions[0].kernel_string(), result_kernel)
    def test_cooperative_binding_fail(self):
        complexes, reactions = read_pil("""
        # File generated by peppercorn-v0.5.0
        
        # Domain Specifications 
        length a = 5
        length b = 5
        length x = 10
        length y = 10
        
        # Resting-set Complexes 
        C = x( y( + b* ) ) a* 
        CR = x( y( + y b( + ) ) ) a* 
        CRF = x( y + y( b( + ) ) ) a* 
        L = a x 
        LC = a( x + x( y( + b* ) ) ) 
        LCF = a( x( + x y( + b* ) ) ) 
        LR = a( x( + y( b( + ) ) ) ) 
        R = y b 
        T = x y 
        
        # Transient Complexes 
        LCR = a( x + x( y( + y b( + ) ) ) ) 
        LCRF1 = a( x( + x y( + y b( + ) ) ) ) 
        LCRF2 = a( x + x( y + y( b( + ) ) ) ) 
        
        # Detailed Reactions 
        reaction [bind21         =      1.5e+06 /M/s ] C + L -> LC
        reaction [bind21         =      1.5e+06 /M/s ] C + R -> CR
        reaction [open           =           20 /s   ] CR -> C + R
        reaction [branch-3way    =           30 /s   ] CR -> CRF
        reaction [branch-3way    =           30 /s   ] CRF -> CR
        reaction [bind21         =      1.5e+06 /M/s ] L + CR -> LCR
        reaction [bind21         =      1.5e+06 /M/s ] L + CRF -> LCRF2
        reaction [open           =           20 /s   ] LC -> C + L
        reaction [branch-3way    =           30 /s   ] LC -> LCF
        reaction [branch-3way    =           30 /s   ] LCF -> LC
        reaction [branch-3way    =           30 /s   ] LCR -> LCRF1
        reaction [branch-3way    =           30 /s   ] LCR -> LCRF2
        reaction [branch-3way    =           30 /s   ] LCRF1 -> LCR
        reaction [branch-3way    =           30 /s   ] LCRF1 -> T + LR
        reaction [branch-3way    =           30 /s   ] LCRF2 -> LCR
        reaction [branch-3way    =           30 /s   ] LCRF2 -> T + LR
        reaction [bind21         =      1.5e+06 /M/s ] R + LC -> LCR
        reaction [bind21         =      1.5e+06 /M/s ] R + LCF -> LCRF1
        """)
        enum = Enumerator(complexes.values())
        enum.enumerate()  # or enum.dry_run()

        enumRG = PepperCondensation(enum)

        # TODO: It should raise an error here, saying that the condensed graph
        # is disconnected!

        #with self.assertRaises(c.CondensationError):
        enumRG.condense()

        self.assertEqual(enumRG.condensed_reactions, [])
    def test_max_helix_02(self):
        complexes, reactions = read_pil("""
        length d1 = 15
        length d4 = 15
        length d6 = 15
        length d7 = 15
        length h8 = 15
        length t0 = 6
        length t2 = 6
        length t3 = 6
        length t5 = 6

        # Initial Complexes
        B2 = d7 t3 d4 t5 
        helper = t3 d7 t3
        PR_FL_B2  = d1 t2( d6( + d7( t3( d4 t5 + ) ) t3* ) )  @ initial 0 M
        
        # Intermediate Complexes
        PR_FLh1B2 = d1 t2( d6( + t3( d7 t3 + d7( t3( d4 t5 + ) ) ) ) )  @ initial 0 M
        PR_FLh2B2 = d1 t2( d6( + t3 d7 t3( + d7( t3( d4 t5 + ) ) ) ) )  @ initial 0 M
        PR_FL_h1w = d1 t2( d6( + t3( d7( t3( + ) ) ) ) )  @ initial 0 M
        
        # sidestuff
        PR_FLB2B2 = d1 t2( d6( + d7 t3( d4 t5 + d7( t3( d4 t5 + ) ) ) ) )  @ initial 0 M

        # casey-semantics
        PR_FLh2B2_v2 = d1 t2( d6( + t3( d7( t3 + d7 t3( d4 t5 + ) ) ) ) )  @ initial 0 M
        PR_FLh2w =     d1 t2( d6( + t3( d7( t3 + t3* ) ) ) )  @ initial 0 M

        """)
        B2 = complexes['B2']
        helper = complexes['helper']
        PR_FL_B2 = complexes['PR_FL_B2']
        PR_FLh1B2 = complexes['PR_FLh1B2']
        PR_FLh2B2 = complexes['PR_FLh2B2']
        PR_FL_h1w = complexes['PR_FL_h1w']
        PR_FLB2B2 = complexes['PR_FLB2B2']
        PR_FLh2B2_v2 = complexes['PR_FLh2B2_v2']
        PR_FLh2w = complexes['PR_FLh2w']

        path1 = PepperReaction([PR_FL_B2, helper], [PR_FLh1B2], 'bind21')
        path1r = PepperReaction([PR_FLh1B2], [PR_FL_B2, helper], 'open')
        path2 = PepperReaction([PR_FL_B2, helper], [PR_FLh2B2], 'bind21')
        path2r = PepperReaction([PR_FLh2B2], [PR_FL_B2, helper], 'open')
        path3 = PepperReaction([PR_FLh1B2], [PR_FL_h1w, B2], 'branch-3way')
        path4 = PepperReaction([PR_FL_B2, B2], [PR_FLB2B2], 'bind21')
        path4r = PepperReaction([PR_FLB2B2], [PR_FL_B2, B2], 'open')
        path5 = PepperReaction([PR_FLh1B2], [PR_FLh2B2], 'branch-3way')
        path6 = PepperReaction([PR_FLh2B2], [PR_FLh1B2], 'branch-3way')

        enum = Enumerator([B2, helper, PR_FL_B2])
        enum.max_helix = True
        enum.enumerate()
        assert sorted(enum.reactions) == sorted(
            [path1, path1r, path2, path2r, path3, path4, path4r, path5, path6])
Example #11
0
    def test_condense_simple(self):
        complexes, reactions = read_pil("""
        # File generated by peppercorn-v0.5.0
        
        # Domain Specifications 
        length d1 = 15
        length t0 = 5
        
        # Resting-set Complexes 
        c1 = t0 d1 
        c2 = d1( + ) t0* 
        c4 = t0( d1( + ) ) 
        c5 = d1 
        
        # Transient Complexes 
        c3 = t0( d1 + d1( + ) ) 
        
        # Detailed Reactions 
        reaction [bind21         =      100 /M/s ] c1 + c2 -> c3
        reaction [open           =       50 /s   ] c3 -> c1 + c2
        reaction [branch-3way    =       50 /s   ] c3 -> c4 + c5
        """)

        # (rs1) c1                c4 (rs3)
        #         \              /
        #          <---> c3 ---->
        #         /              \
        # (rs2) c2                c5 (rs4)

        enum = Enumerator(complexes.values(), reactions)
        enum.enumerate() 
        enum.condense()
        for con in enum.condensed_reactions:
            assert con.rate_constant[0] == 50
        del enum

        # old interface ...
        c1 = PepperMacrostate([complexes['c1']])
        c2 = PepperMacrostate([complexes['c2']])
        c4 = PepperMacrostate([complexes['c4']])
        c5 = PepperMacrostate([complexes['c5']])
        cond_react = PepperReaction([c1, c2], [c4, c5], 'condensed')
        cond_react.rate_constant = 20, None

        enum = Enumerator(complexes.values(), reactions)
        enum.dry_run()
        enumRG = PepperCondensation(enum)
        enumRG.condense()
        for con in enumRG.condensed_reactions:
            assert con.rate_constant[0] == 20
    def test_interface_01(self):
        PepperComplex.PREFIX = 'enum'
        complexes, reactions = read_pil("""
        # Domain Specifications
        length a = 8
        length b = 8
        length c = 8
        length d2 = 8
        length d3 = 8
        length t = 4

        # Resting-set Complexes
        e0 = d2( d3( + ) a* + a*( b*( c ) ) ) t* 
        e12 = d2 d3( + ) a*                     
        e13 = t( d2( d3 + a*( b*( c ) ) ) )    
        e21 = d2 d3                           
        e22 = t( d2( d3( + ) a*( + a* b*( c ) ) ) )
        e27 = t( d2( d3( + ) a* + a*( b*( c ) ) ) )
        gate = d2( d3( + ) a*( + a* b*( c ) ) ) t* 
        t23 = t d2 d3   
                                                                                                     
        # Transient Complexes    
        e5 = t( d2 d3 + d2( d3( + ) a*( + a* b*( c ) ) ) )  
        e7 = t( d2 d3 + d2( d3( + ) a* + a*( b*( c ) ) ) ) 
        e18 = t( d2( d3 + d2 d3( + ) a*( + a* b*( c ) ) ) )

        # Detailed Reactions  
        reaction [bind21         =      1.2e+06 /M/s ] e0 + t23 -> e7   
        reaction [branch-3way    =     0.122307 /s   ] e0 -> gate       
        reaction [branch-3way    =      41.6667 /s   ] e5 -> e7         
        reaction [branch-3way    =      41.6667 /s   ] e5 -> e18        
        reaction [open           =      306.345 /s   ] e5 -> t23 + gate 
        reaction [open           =      306.345 /s   ] e7 -> e0 + t23   
        reaction [branch-3way    =     0.122307 /s   ] e7 -> e5         
        reaction [branch-3way    =      41.6667 /s   ] e7 -> e12 + e13  
        reaction [branch-3way    =     0.122307 /s   ] e18 -> e5        
        reaction [branch-3way    =      41.6667 /s   ] e18 -> e12 + e13 
        reaction [branch-3way    =     0.122307 /s   ] e18 -> e22 + e21 
        reaction [branch-3way    =      41.6667 /s   ] e22 -> e27       
        reaction [branch-3way    =     0.122307 /s   ] e27 -> e22       
        reaction [branch-3way    =      41.6667 /s   ] gate -> e0       
        reaction [bind21         =      1.2e+06 /M/s ] t23 + gate -> e5 
        """)

        enum = Enumerator(complexes.values(), reactions)
        enum.release_cutoff = 7
        enum.enumerate()
        self.assertEqual(sorted(enum.reactions), sorted(reactions))
    def test_sarma_fig4_CRN(self):
        complexes = self.complexes
        reactions = self.reactions
        cplx = self.cplx
        rxn = self.rxn
        rs = self.rs

        rxn('top + bot -> e27 ', k=4.5e+06, rtype='bind21     ')
        rxn('com1 + e29 -> e33', k=1.5e+06, rtype='bind21     ')
        rxn('bot + com2 -> e29', k=4.5e+06, rtype='bind21     ')
        rxn('com1 + com2 -> e1', k=1.5e+06, rtype='bind21     ')
        rxn('e1 -> com1 + com2', k=21.7122, rtype='open       ')
        rxn('e1 -> e6 + e7    ', k=9.52381, rtype='branch-3way')
        rxn('e1 -> e8         ', k=22.2222, rtype='branch-3way')
        rxn('e6 + bot -> e31  ', k=4.5e+06, rtype='bind21     ')
        rxn('e7 -> e15        ', k=22.2222, rtype='branch-3way')
        rxn('e8 -> e1         ', k=22.2222, rtype='branch-3way')
        rxn('e8 -> e6 + e15   ', k=9.52381, rtype='branch-3way')
        rxn('e8 -> e10 + e11  ', k=21.7122, rtype='open       ')
        rxn('e10 -> e6 + e17  ', k=9.52381, rtype='branch-3way')
        rxn('e15 -> e7        ', k=22.2222, rtype='branch-3way')
        rxn('e15 -> e17 + e11 ', k=21.7122, rtype='open       ')
        rxn('e17 + e11 -> e15 ', k=1.5e+06, rtype='bind21     ')
        rxn('e33 -> com1 + e29', k=21.7122, rtype='open       ')
        rxn('e33 -> e37       ', k=22.2222, rtype='branch-3way')
        rxn('e33 -> e38       ', k=0.000623053, rtype='branch-4way')
        rxn('e37 -> e33       ', k=22.2222, rtype='branch-3way')
        rxn('e37 -> e43       ', k=0.000623053, rtype='branch-4way')
        rxn('e37 -> e58 + e11 ', k=21.7122, rtype='open       ')
        rxn('e38 -> e31 + e7  ', k=16.6667, rtype='branch-3way')
        rxn('e38 -> e33       ', k=0.000623053, rtype='branch-4way')
        rxn('e38 -> e43       ', k=22.2222, rtype='branch-3way')
        rxn('e43 -> e47 + e11 ', k=21.7122, rtype='open       ')
        rxn('e43 -> e31 + e15 ', k=16.6667, rtype='branch-3way')
        rxn('e43 -> e37       ', k=0.000623053, rtype='branch-4way')
        rxn('e43 -> e38       ', k=22.2222, rtype='branch-3way')
        rxn('e47 -> e31 + e17 ', k=16.6667, rtype='branch-3way')
        rxn('e47 -> e58       ', k=0.000623053, rtype='branch-4way')
        rxn('e58 -> e47       ', k=0.000623053, rtype='branch-4way')

        enum = Enumerator(complexes.values(), list(reactions))
        enum.dry_run()

        enumRG = PepperCondensation(enum)
        enumRG.condense()
    def test_named_complexes(self):
        complexes, reactions = read_pil("""
        sequence t = GGAGCC
        sequence s = ATATAT
        sequence r = GCGCGC
        sequence d2 = GGCAAACAAG
        sequence d3 = CGGCAGAATT
        sequence a = CGCATTTGCC
        sequence b = TACCTTTTCC
        sequence c = CAAAGCCCTT

        A = t d2 s* d3
        B = d2( d3( + ) s*( a* + a*( b*( c ) ) ) ) t*
        B2 = d2( d3( + ) s* a* + a*( b*( c ) ) s ) t* @ initial 0 M
        B3 = d2( d3( + ) s*( a*( + a* b*( c ) ) ) ) t* @ initial 0 M
        B4 = d2( d3( + ) s* a*( + a* b*( c ) ) s ) t* @ initial 0 M

        C = d2 d3( + ) s* a* @initial 0 M
        D = t( d2( s*( d3 + a*( b*( c ) ) ) ) ) @i 0 M
        E = d2 d3 @i 0 M
        F = t( d2( s*( d3( + ) s* a*( + a* b*( c ) ) ) ) ) @i 0 M
        G = t d2 s* d3( + ) s* a* @i 0 M
        """)
        A = complexes['A']
        B = complexes['B']
        F = complexes['F']

        enum = Enumerator([A, B], named_complexes=[A, B, F])
        enum.max_complex_count = 1000
        enum.max_reaction_count = 5000
        enum.enumerate()
        self.assertTrue(
            F in [rms.representative for rms in enum.resting_macrostates])
    def test_interface_02(self):
        complexes, _ = read_pil("""
        length a = 3
        length n = 1
        length b = 1
        length c = 4
        length ab = 4

        X = a( b( c( + ) ) )
        Y = ab( c( + ) )

        Xf = a b( c( + ) ) a*
        Xff= a b c( + ) b* a*
        Xb = a( b( c + c* ) )
        Y1 = ab c( + ) ab*
        Y2 = ab( c + c* )
        """)
        X = complexes['X']
        Y = complexes['Y']

        Xf = complexes['Xf']
        Xff = complexes['Xff']
        Xb = complexes['Xb']
        Y1 = complexes['Y1']
        Y2 = complexes['Y2']

        enum = Enumerator([X, Y], named_complexes=[X, Y, Xf, Xff, Xb, Y1, Y2])
        enum.max_helix = False
        enum.dry_run()
        self.assertEqual(sorted(enum.complexes), sorted([X, Y]))
        self.assertEqual(sorted(enum.resting_complexes), sorted([X, Y]))
        self.assertEqual(
            sorted(r.representative for r in enum.resting_macrostates),
            sorted([X, Y]))
        enum.enumerate()
        assert len(list(enum.complexes)) == 16
        with self.assertRaises(PeppercornUsageError) as e:
            enum.dry_run()
    def test_cooperative_binding(self):
        complexes, reactions = read_pil("""
        length a = 5
        length x = 10
        length y = 10
        length b = 5

        C = x( y( + b* ) ) a*
        L = a x
        R = y b
        T = x y

        LC = a( x + x( y( + b* ) ) )
         CR = x( y( + y b( + ) ) ) a*
        LCR = a( x + x( y( + y b( + ) ) ) )
        LCF = a( x( + x y( + b* ) ) )
         CRF = x( y + y( b( + ) ) ) a*

        LCRF1 = a( x( + x y( + y b( + ) ) ) )
        LCRF2 = a( x + x( y + y( b( + ) ) ) )
        LR = a( x( + y( b( + ) ) ) )
        """)

        C = complexes['C']
        L = complexes['L']
        R = complexes['R']
        T = complexes['T']
        LC = complexes['LC']
        LCF = complexes['LCF']
        CR = complexes['CR']
        CRF = complexes['CRF']
        LCRF1 = complexes['LCRF1']
        LR = complexes['LR']

        path1 = PepperReaction([L, C], [LC], 'bind21')
        path1r = PepperReaction([LC], [L, C], 'open')
        path2 = PepperReaction([LC], [LCF], 'branch-3way')
        path3 = PepperReaction([R, LCF], [LCRF1], 'bind21')
        path4 = PepperReaction([LCRF1], [LR, T], 'branch-3way')

        enum = Enumerator(list(complexes.values()))
        enum.k_fast = float('inf')
        enum.k_slow = 0
        enum.max_helix = True
        enum.enumerate()
        self.assertEqual(len(list(enum.reactions)), 22)
    def test_simple(self):
        complexes, reactions = read_pil("""
        length a = 6
        length a1 = 2
        length a2 = 2
        length a3 = 2
        length b  = 24
        length b1 = 8
        length b2 = 8
        length b3 = 8
        length c  = 24
        length c1 = 8
        length c2 = 8
        length c3 = 8

        I = a b c
        C = b( c( + ) ) a*
        J = a( b c + b( c( + ) ) )
        D = a( b( c( + ) ) )

        cI = a1 a2 a3 b1 b2 b3 c1 c2 c3
        cC = b1( b2( b3( c1( c2( c3( + ) ) ) ) ) ) a3* a2* a1*
        cJ = a1( a2( a3( b1 b2 b3 c1 c2 c3 + b1( b2( b3( c1( c2( c3( + ) ) ) ) ) ) ) ) )
        cD = a1( a2( a3( b1( b2( b3( c1( c2( c3( + ) ) ) ) ) ) ) ) )
        """)

        enum = Enumerator(
            [complexes['I'], complexes['C'], complexes['J'], complexes['D']],
            named_complexes=list(complexes.values()))
        enum.k_fast = 0
        enum.k_slow = 0
        enum.max_helix = True
        enum.enumerate()

        enum2 = Enumerator([
            complexes['cI'], complexes['cC'], complexes['cJ'], complexes['cD']
        ],
                           named_complexes=list(complexes.values()))
        enum.k_fast = 0
        enum2.k_fast = 0
        enum2.k_slow = 0
        enum2.max_helix = True
        enum2.enumerate()

        self.assertEqual(len(list(enum2.reactions)), len(list(enum.reactions)))
    def test_max_helix_01(self):
        complexes, reactions = read_pil("""
        length a = 15
        length x = 15
        length x1 = 15
        length x2 = 15
        length y = 15
        length y1 = 15
        length y2 = 15
        length z = 15
        length z1 = 15
        length z2 = 15

        # should be one reaction, is one
        A1 = x( y z + y( z( + ) ) )
        A1_2 = x( y( z( + ) ) )
        YZ = y z

        # should be one reactions, is one
        B1 = x1( x2( y1 y2 z1 z2 + y1( y2( z1( z2( + ) ) ) ) ) ) 
        B1_2 = x1( x2( y1( y2( z1( z2( + ) ) ) ) ) ) 
        YZ2 = y1 y2 z1 z2

        # should be two reactions, is two
        A2   = x( y z + y( + z( + ) ) )
        A2_1 = x( y( z + z( + ) ) )
        #A2_2 = x( y( z( + ) ) ) # = A1_2
        Y1 = y
        Z1 = z

        # should be two reactions, is two
        B2 = x1( x2( y1 y2 z1 z2 + y1( y2( + z1( z2( + ) ) ) ) ) ) 
        B2_1 = x1( x2( y1( y2( z1 z2 + z1( z2( + ) ) ) ) ) ) 
        Y2 = y1 y2
        Z2 = z1 z2

        # should be two reactions, is two
        C = x( y z + y( + a( + ) z( + ) ) )
        C1 = x( y( z + a( + ) z( + ) ) )
        r1 = a( + ) z

        """)

        A1 = complexes['A1']
        A1_2 = complexes['A1_2']
        YZ = complexes['YZ']

        A2 = complexes['A2']
        A2_1 = complexes['A2_1']
        #A2_2 = complexes['A2_2']
        Y1 = complexes['Y1']
        Z1 = complexes['Z1']

        enum = Enumerator([A1, A2])
        enum.k_fast = 0
        enum.k_slow = 0
        enum.max_helix = True
        enum.enumerate()

        path1 = PepperReaction([A1], sorted([A1_2, YZ]), 'branch-3way')
        path2 = PepperReaction([A2], sorted([A2_1, Y1]), 'branch-3way')
        path3 = PepperReaction([A2_1], sorted([A1_2, Z1]), 'branch-3way')
        self.assertEqual(sorted(enum.reactions), sorted([path1, path2, path3]))

        B1 = complexes['B1']
        B1_2 = complexes['B1_2']
        YZ2 = complexes['YZ2']

        B2 = complexes['B2']
        B2_1 = complexes['B2_1']
        Y2 = complexes['Y2']
        Z2 = complexes['Z2']

        enum = Enumerator([B1, B2])
        enum.k_fast = 0
        enum.k_slow = 0
        enum.max_helix = True
        enum.enumerate()

        path1 = PepperReaction([B1], sorted([B1_2, YZ2]), 'branch-3way')
        path2 = PepperReaction([B2], sorted([B2_1, Y2]), 'branch-3way')
        path3 = PepperReaction([B2_1], sorted([B1_2, Z2]), 'branch-3way')
        self.assertEqual(sorted(enum.reactions), sorted([path1, path2, path3]))

        C = complexes['C']
        enum = Enumerator([C])
        enum.k_fast = 0
        enum.k_slow = 0
        enum.max_helix = True
        enum.enumerate()
        self.assertEqual(len(list(enum.reactions)), 2)
    def test_sarma_fig4_v1(self):
        complexes, reactions = read_pil("""
        # File generated by peppercorn-v0.5.0

        # Domain Specifications 
        length d1 = 15
        length d2 = 15
        length d3 = 5
        length d4 = 15
        length d5 = 5
        length d6 = 15
        length d7 = 5

        # Resting-set Complexes 
        bot = d1* 
        com1 = d3*( d2*( d1*( d5 d6 + ) ) ) d4 
        com2 = d6( d7( + ) ) d5* d1 d2 d3 
        e6 = d1 d2 d3 d4 
        e11 = d6 d7 
        e17 = d7* d6*( d5*( d1( d2( d3( + ) ) ) ) ) 
        e27 = d1*( + ) 
        e29 = d1*( + d6( d7( + ) ) d5* ) d2 d3 
        e31 = d1*( + ) d2 d3 d4 
        top = d1 

        # Transient Complexes 
        e1 = d6( d7( + ) ) d5*( d1 d2 d3 + d1( d2( d3( d4 + ) ) ) ) d6 
        e7 = d6( d7( + ) ) d5*( d1( d2( d3( + ) ) ) ) d6 
        e8 = d6 d7( + ) d6*( d5*( d1 d2 d3 + d1( d2( d3( d4 + ) ) ) ) ) 
        e10 = d7* d6*( d5*( d1 d2 d3 + d1( d2( d3( d4 + ) ) ) ) ) 
        e15 = d6 d7( + ) d6*( d5*( d1( d2( d3( + ) ) ) ) ) 
        e33 = d6( d7( + ) ) d5*( d1( d2 d3 + ) + d1( d2( d3( d4 + ) ) ) ) d6 
        e37 = d6 d7( + ) d6*( d5*( d1( d2 d3 + ) + d1( d2( d3( d4 + ) ) ) ) ) 
        e38 = d6( d7( + ) ) d5*( d1( d2 d3 + d1*( + ) d2( d3( d4 + ) ) ) ) d6 
        e43 = d6 d7( + ) d6*( d5*( d1( d2 d3 + d1*( + ) d2( d3( d4 + ) ) ) ) ) 
        e47 = d7* d6*( d5*( d1( d2 d3 + d1*( + ) d2( d3( d4 + ) ) ) ) ) 
        e58 = d7* d6*( d5*( d1( d2 d3 + ) + d1( d2( d3( d4 + ) ) ) ) ) 

        # Detailed Reactions 
        reaction [bind21         =      4.5e+06 /M/s ] bot + top -> e27
        reaction [bind21         =      1.5e+06 /M/s ] com1 + e29 -> e33
        reaction [bind21         =      4.5e+06 /M/s ] com2 + bot -> e29
        reaction [bind21         =      1.5e+06 /M/s ] com2 + com1 -> e1
        reaction [open           =      21.7122 /s   ] e1 -> com2 + com1
        reaction [branch-3way    =      9.52381 /s   ] e1 -> e6 + e7
        reaction [branch-3way    =      22.2222 /s   ] e1 -> e8
        reaction [bind21         =      4.5e+06 /M/s ] e6 + bot -> e31
        reaction [branch-3way    =      22.2222 /s   ] e7 -> e15
        reaction [branch-3way    =      22.2222 /s   ] e8 -> e1
        reaction [branch-3way    =      9.52381 /s   ] e8 -> e6 + e15
        reaction [open           =      21.7122 /s   ] e8 -> e10 + e11
        reaction [branch-3way    =      9.52381 /s   ] e10 -> e6 + e17
        reaction [branch-3way    =      22.2222 /s   ] e15 -> e7
        reaction [open           =      21.7122 /s   ] e15 -> e17 + e11
        reaction [bind21         =      1.5e+06 /M/s ] e17 + e11 -> e15
        reaction [open           =      21.7122 /s   ] e33 -> com1 + e29
        reaction [branch-3way    =      22.2222 /s   ] e33 -> e37
        reaction [branch-4way    =  0.000623053 /s   ] e33 -> e38
        reaction [branch-3way    =      22.2222 /s   ] e37 -> e33
        reaction [branch-4way    =  0.000623053 /s   ] e37 -> e43
        reaction [open           =      21.7122 /s   ] e37 -> e58 + e11
        reaction [branch-3way    =      16.6667 /s   ] e38 -> e7 + e31
        reaction [branch-4way    =  0.000623053 /s   ] e38 -> e33
        reaction [branch-3way    =      22.2222 /s   ] e38 -> e43
        reaction [open           =      21.7122 /s   ] e43 -> e11 + e47
        reaction [branch-3way    =      16.6667 /s   ] e43 -> e15 + e31
        reaction [branch-4way    =  0.000623053 /s   ] e43 -> e37
        reaction [branch-3way    =      22.2222 /s   ] e43 -> e38
        reaction [branch-3way    =      16.6667 /s   ] e47 -> e17 + e31
        reaction [branch-4way    =  0.000623053 /s   ] e47 -> e58
        reaction [branch-4way    =  0.000623053 /s   ] e58 -> e47
        """)

        enum = Enumerator(complexes.values(), reactions)
        #enum.enumerate() # or
        enum.dry_run()
        self.assertEqual(sorted(enum.reactions), sorted(reactions))

        enumRG = PepperCondensation(enum)
        enumRG.condense()
    def test_fate_example(self):
        # TODO: needs more testing, also remove the PREFIX part and replace with
        # non-auto-prefix complex names...
        PepperComplex.PREFIX = 'enum'
        complexes, reactions = read_pil("""
        # File generated by peppercorn-v0.5.0

        # Domain Specifications 
        length a = 8
        length b = 8
        length c = 8
        length d2 = 8
        length d3 = 8
        length t = 4

        # Resting-set Complexes 
        e0 = d2( d3( + ) a* + a*( b*( c ) ) ) t* 
        e12 = d2 d3( + ) a* 
        e13 = t( d2( d3 + a*( b*( c ) ) ) ) 
        e21 = d2 d3 
        e22 = t( d2( d3( + ) a*( + a* b*( c ) ) ) ) 
        e27 = t( d2( d3( + ) a* + a*( b*( c ) ) ) ) 
        gate = d2( d3( + ) a*( + a* b*( c ) ) ) t* 
        t23 = t d2 d3 

        # Transient Complexes 
        e5 = t( d2 d3 + d2( d3( + ) a*( + a* b*( c ) ) ) ) 
        e7 = t( d2 d3 + d2( d3( + ) a* + a*( b*( c ) ) ) ) 
        e18 = t( d2( d3 + d2 d3( + ) a*( + a* b*( c ) ) ) ) 

        # Detailed Reactions 
        reaction [bind21         =      1.2e+06 /M/s ] e0 + t23 -> e7
        reaction [branch-3way    =     0.122307 /s   ] e0 -> gate
        reaction [branch-3way    =      41.6667 /s   ] e5 -> e7
        reaction [branch-3way    =      41.6667 /s   ] e5 -> e18
        reaction [open           =      306.345 /s   ] e5 -> t23 + gate
        reaction [open           =      306.345 /s   ] e7 -> e0 + t23
        reaction [branch-3way    =     0.122307 /s   ] e7 -> e5
        reaction [branch-3way    =      41.6667 /s   ] e7 -> e12 + e13
        reaction [branch-3way    =     0.122307 /s   ] e18 -> e5
        reaction [branch-3way    =      41.6667 /s   ] e18 -> e12 + e13
        reaction [branch-3way    =     0.122307 /s   ] e18 -> e22 + e21
        reaction [branch-3way    =      41.6667 /s   ] e22 -> e27
        reaction [branch-3way    =     0.122307 /s   ] e27 -> e22
        reaction [branch-3way    =      41.6667 /s   ] gate -> e0
        reaction [bind21         =      1.2e+06 /M/s ] t23 + gate -> e5
        """)
        gate = complexes['gate']
        t23 = complexes['t23']
        enum = Enumerator(complexes.values())
        enum.enumerate()  # or enum.dry_run()

        self.assertEqual(sorted(enum.reactions), sorted(reactions))
        """
        # Resting sets 
        state re0 = [e0, gate]
        state re12 = [e12]
        state re13 = [e13]
        state re21 = [e21]
        state re22 = [e22, e27]
        state rt23 = [t23]

        reaction [condensed      =       287342 /M/s ] re0 + rt23 -> re13 + re12
        reaction [condensed      =      2.45499 /M/s ] re0 + rt23 -> re21 + re22
        """

        enumRG = PepperCondensation(enum)
        enumRG.condense()
        self.assertEqual(len(enumRG.resting_sets), 6)
        self.assertEqual(len(enumRG.condensed_reactions), 2)

        PepperComplex.PREFIX = 'e'
    def test_cooperative_binding(self):
        # cooperative binding with k-fast 25
        complexes, reactions = read_pil("""
        # File generated by peppercorn-v0.5.0
        
        # Domain Specifications 
        length a = 5
        length b = 5
        length x = 10
        length y = 10
        
        # Resting-set Complexes 
        C = x( y( + b* ) ) a* 
        CR = x( y( + y b( + ) ) ) a* 
        CRF = x( y + y( b( + ) ) ) a* 
        L = a x 
        LC = a( x + x( y( + b* ) ) ) 
        LCF = a( x( + x y( + b* ) ) ) 
        LR = a( x( + y( b( + ) ) ) ) 
        R = y b 
        T = x y 
        
        # Transient Complexes 
        LCR = a( x + x( y( + y b( + ) ) ) ) 
        LCRF1 = a( x( + x y( + y b( + ) ) ) ) 
        LCRF2 = a( x + x( y + y( b( + ) ) ) ) 
        
        # Detailed Reactions 
        reaction [bind21         =      1.5e+06 /M/s ] C + L -> LC
        reaction [bind21         =      1.5e+06 /M/s ] C + R -> CR
        reaction [open           =           20 /s   ] CR -> C + R
        reaction [branch-3way    =           30 /s   ] CR -> CRF
        reaction [branch-3way    =           30 /s   ] CRF -> CR
        reaction [bind21         =      1.5e+06 /M/s ] L + CR -> LCR
        reaction [bind21         =      1.5e+06 /M/s ] L + CRF -> LCRF2
        reaction [open           =           20 /s   ] LC -> C + L
        reaction [branch-3way    =           30 /s   ] LC -> LCF
        reaction [branch-3way    =           30 /s   ] LCF -> LC
        reaction [branch-3way    =           30 /s   ] LCR -> LCRF1
        reaction [branch-3way    =           30 /s   ] LCR -> LCRF2
        reaction [branch-3way    =           30 /s   ] LCRF1 -> LCR
        reaction [branch-3way    =           30 /s   ] LCRF1 -> T + LR
        reaction [branch-3way    =           30 /s   ] LCRF2 -> LCR
        reaction [branch-3way    =           30 /s   ] LCRF2 -> T + LR
        reaction [bind21         =      1.5e+06 /M/s ] R + LC -> LCR
        reaction [bind21         =      1.5e+06 /M/s ] R + LCF -> LCRF1
        """)
        L = complexes['L']
        C = complexes['C']
        R = complexes['R']
        T = complexes['T']
        LR = complexes['LR']
        LC = complexes['LC']
        CR = complexes['CR']
        CRF = complexes['CRF']
        LCF = complexes['LCF']
        LCR = complexes['LCR']
        LCRF1 = complexes['LCRF1']
        LCRF2 = complexes['LCRF2']

        # always resting sets
        rs1 = PepperMacrostate([L], memorycheck=False)
        rs2 = PepperMacrostate([C], memorycheck=False)
        rs3 = PepperMacrostate([R], memorycheck=False)
        rs4 = PepperMacrostate([T], memorycheck=False)
        rs5 = PepperMacrostate([LR], memorycheck=False)

        rs6 = PepperMacrostate([CR, CRF], memorycheck=False)
        rs7 = PepperMacrostate([LC, LCF], memorycheck=False)

        cplx_to_fate = {  # maps Complex to its SetOfFates
            L: SetOfFates([[rs1]]),
            C: SetOfFates([[rs2]]),
            R: SetOfFates([[rs3]]),
            T: SetOfFates([[rs4]]),
            LR: SetOfFates([[rs5]]),
            CR: SetOfFates([[rs6]]),
            CRF: SetOfFates([[rs6]]),
            LC: SetOfFates([[rs7]]),
            LCF: SetOfFates([[rs7]]),
            #NOTE: only rs4 and rs5 bec. the other unimolecular reactions are now slow!!
            LCR: SetOfFates([[rs4, rs5]]),
            LCRF1: SetOfFates([[rs4, rs5]]),
            LCRF2: SetOfFates([[rs4, rs5]])
        }

        cr1 = PepperReaction([rs1, rs2], [rs7],
                             'condensed',
                             rate=1.5e6,
                             memorycheck=False)
        cr2 = PepperReaction([rs2, rs3], [rs6],
                             'condensed',
                             rate=1.5e6,
                             memorycheck=False)

        # not sure how these rates were computed...
        cr1r = PepperReaction([rs7], [rs1, rs2],
                              'condensed',
                              rate=10.0,
                              memorycheck=False)
        cr2r = PepperReaction([rs6], [rs2, rs3],
                              'condensed',
                              rate=10.0,
                              memorycheck=False)
        cr3 = PepperReaction([rs1, rs6], [rs5, rs4],
                             'condensed',
                             rate=3e6 / 2,
                             memorycheck=False)
        cr4 = PepperReaction([rs3, rs7], [rs5, rs4],
                             'condensed',
                             rate=3e6 / 2,
                             memorycheck=False)

        enum = Enumerator(complexes.values(), reactions)

        enum.k_fast = 25

        #enum.enumerate() # or enum.dry_run()
        enum.dry_run()  # or enum.dry_run()

        enumRG = PepperCondensation(enum)
        enumRG.condense()

        # Works...
        self.assertEqual(enum.k_fast, enumRG.k_fast)
        self.assertEqual(sorted([rs1, rs2, rs3, rs4, rs5, rs6, rs7]),
                         sorted(enumRG.resting_sets))

        self.assertDictEqual(cplx_to_fate, enumRG.cplx_to_fate)
        self.assertEqual(sorted([cr1, cr1r, cr2, cr2r, cr3, cr4]),
                         sorted(enumRG.condensed_reactions))

        for (r1, r2) in zip(sorted([cr1, cr1r, cr2, cr2r, cr3, cr4]),
                            sorted(enumRG.condensed_reactions)):
            self.assertEqual(r1, r2)
            self.assertAlmostEqual(r1.rate, r2.rate)
    def test_zhang_cooperative_binding(self):
        complexes, reactions = read_pil("""
        # Figure 1 of David Yu Zhang, "Cooperative hybridization of oligonucleotides", JACS, 2012

        # File generated by peppercorn-v0.5.0

        # Domain Specifications 
        length d1 = 8
        length d2 = 18
        length d3 = 18
        length d4 = 8

        # Resting-set Complexes 
        C1 = d2( d3( + d4* ) ) d1* 
        L1 = d1( d2 + d2( d3( + d4* ) ) ) 
        L2 = d1( d2( + d2 d3( + d4* ) ) ) 
        Out = d2 d3 
        R1 = d2( d3( + d3 d4( + ) ) ) d1* 
        R2 = d2( d3 + d3( d4( + ) ) ) d1* 
        T1 = d1 d2 
        T2 = d3 d4 
        Waste = d1( d2( + d3( d4( + ) ) ) ) 

        # Transient Complexes 
        L1R1 = d1( d2 + d2( d3( + d3 d4( + ) ) ) ) 
        L1R2 = d1( d2 + d2( d3 + d3( d4( + ) ) ) ) 
        L2R1 = d1( d2( + d2 d3( + d3 d4( + ) ) ) ) 

        # Detailed Reactions 
        reaction [bind21         =      2.4e+06 /M/s ] C1 + T2 -> R1
        reaction [bind21         =      2.4e+06 /M/s ] L1 + T2 -> L1R1
        reaction [branch-3way    =      18.5185 /s   ] L1 -> L2
        reaction [branch-3way    =      18.5185 /s   ] L1R1 -> L1R2
        reaction [branch-3way    =      18.5185 /s   ] L1R1 -> L2R1
        reaction [branch-3way    =      18.5185 /s   ] L1R2 -> L1R1
        reaction [branch-3way    =      18.5185 /s   ] L1R2 -> Waste + Out
        reaction [bind21         =      2.4e+06 /M/s ] L2 + T2 -> L2R1
        reaction [branch-3way    =      18.5185 /s   ] L2 -> L1
        reaction [branch-3way    =      18.5185 /s   ] L2R1 -> L1R1
        reaction [branch-3way    =      18.5185 /s   ] L2R1 -> Waste + Out
        reaction [branch-3way    =      18.5185 /s   ] R1 -> R2
        reaction [branch-3way    =      18.5185 /s   ] R2 -> R1
        reaction [bind21         =      2.4e+06 /M/s ] T1 + C1 -> L1
        reaction [bind21         =      2.4e+06 /M/s ] T1 + R1 -> L1R1
        reaction [bind21         =      2.4e+06 /M/s ] T1 + R2 -> L1R2
        """)

        enum = Enumerator(complexes.values(), reactions)
        enum.k_fast = 0.01
        enum.release_cutoff = 10
        #enum.enumerate() # or enum.dry_run()
        enum.dry_run()

        enumRG = PepperCondensation(enum)
        enumRG.condense()
        """
        macrostate rC1 = [C1]
        macrostate rL2 = [L2, L1]
        macrostate rOut = [Out]
        macrostate rR1 = [R1, R2]
        macrostate rT1 = [T1]
        macrostate rT2 = [T2]
        macrostate rWaste = [Waste]

        reaction [condensed      =      2.4e+06 /M/s ] rT1 + rC1 -> rL2
        reaction [condensed      =      2.4e+06 /M/s ] rL2 + rT2 -> rWaste + rOut
        reaction [condensed      =      2.4e+06 /M/s ] rC1 + rT2 -> rR1
        reaction [condensed      =      2.4e+06 /M/s ] rT1 + rR1 -> rWaste + rOut
        reaction [condensed      =   0.00316623 /s   ] rL2 -> rT1 + rC1
        reaction [condensed      =   0.00316623 /s   ] rR1 -> rC1 + rT2
        """

        L1 = complexes['L1']
        L2 = complexes['L2']
        rL2 = PepperMacrostate([L2, L1], memorycheck=False)
        Out = complexes['Out']
        rOut = PepperMacrostate([Out], memorycheck=False)
        Waste = complexes['Waste']
        rWaste = PepperMacrostate([Waste], memorycheck=False)
        T2 = complexes['T2']
        rT2 = PepperMacrostate([T2], memorycheck=False)

        # calculated by hand...
        cr1 = PepperReaction([rL2, rT2], [rWaste, rOut],
                             'condensed',
                             rate=2.4e6,
                             memorycheck=False)

        found = False
        for r in enumRG.condensed_reactions:
            if r == cr1:
                found = True
                self.assertAlmostEqual(r.rate, cr1.rate)

        self.assertTrue(found)
    def test_condense_simple(self):
        complexes, reactions = read_pil("""
        # File generated by peppercorn-v0.5.0
        
        # Domain Specifications 
        length d1 = 15
        length t0 = 5
        
        # Resting-set Complexes 
        c1 = t0 d1 
        c2 = d1( + ) t0* 
        c4 = t0( d1( + ) ) 
        c5 = d1 
        
        # Transient Complexes 
        c3 = t0( d1 + d1( + ) ) 
        
        # Detailed Reactions 
        reaction [bind21         =      100 /M/s ] c1 + c2 -> c3
        reaction [open           =       50 /s   ] c3 -> c1 + c2
        reaction [branch-3way    =       50 /s   ] c3 -> c4 + c5
        """)

        # (rs1) c1                c4 (rs3)
        #         \              /
        #          <---> c3 ---->
        #         /              \
        # (rs2) c2                c5 (rs4)

        # RestingSet representation
        rs1 = PepperMacrostate([complexes['c1']], memorycheck=False)
        rs2 = PepperMacrostate([complexes['c2']], memorycheck=False)
        rs3 = PepperMacrostate([complexes['c4']], memorycheck=False)
        rs4 = PepperMacrostate([complexes['c5']], memorycheck=False)

        # Frozensets instead of RestingMacrostates
        fs1 = frozenset([complexes['c1']])
        fs2 = frozenset([complexes['c2']])
        fs3 = frozenset([complexes['c4']])
        fs4 = frozenset([complexes['c5']])

        cplx_to_state = {  # maps Complex to its RestingMacrostate
            complexes['c1']: rs1,
            complexes['c2']: rs2,
            complexes['c4']: rs3,
            complexes['c5']: rs4
        }

        cplx_to_fate = {  # maps Complex to its SetOfFates
            complexes['c1']: SetOfFates([[rs1]]),
            complexes['c2']: SetOfFates([[rs2]]),
            complexes['c3']: SetOfFates([[rs1, rs2], [rs3, rs4]]),
            complexes['c4']: SetOfFates([[rs3]]),
            complexes['c5']: SetOfFates([[rs4]])
        }

        cplx_to_set = {  # maps Complex to its frozenset
            complexes['c1']: fs1,
            complexes['c2']: fs2,
            complexes['c4']: fs3,
            complexes['c5']: fs4
        }

        set_to_fate = {  # maps frozenset to the RestingMacrostate
            fs1: rs1,
            fs2: rs2,
            fs3: rs3,
            fs4: rs4
        }

        cond_react = PepperReaction([rs1, rs2], [rs3, rs4],
                                    'condensed',
                                    memorycheck=False)
        cond_react.rate = 100 * (float(50) / (50 + 50))

        enum = Enumerator(complexes.values(), reactions)
        enum.dry_run()  # does not change the rates!

        enumRG = PepperCondensation(enum)
        enumRG.condense()

        self.assertEqual(sorted([rs1, rs2, rs3, rs4]),
                         sorted(enumRG.resting_sets))
        self.assertDictEqual(set_to_fate, enumRG.set_to_fate)
        self.assertDictEqual(cplx_to_fate, enumRG.cplx_to_fate)
        #self.assertDictEqual(cplx_to_set,  info['complexes_to_resting_set'])

        self.assertEqual([cond_react], enumRG.condensed_reactions)
        self.assertEqual(cond_react.rate, enumRG.condensed_reactions[0].rate)
        self.assertEqual(enumRG.condensed_reactions[0].rate, 50)
Example #24
0
    def test_zhang_cooperative_binding(self):
        complexes, reactions = read_pil("""
        # Figure 1 of David Yu Zhang, "Cooperative hybridization of oligonucleotides", JACS, 2012

        # File generated by peppercorn-v0.5.0

        # Domain Specifications 
        length d1 = 8
        length d2 = 18
        length d3 = 18
        length d4 = 8

        # Resting-set Complexes 
        C1 = d2( d3( + d4* ) ) d1* 
        L1 = d1( d2 + d2( d3( + d4* ) ) ) 
        L2 = d1( d2( + d2 d3( + d4* ) ) ) 
        Out = d2 d3 
        R1 = d2( d3( + d3 d4( + ) ) ) d1* 
        R2 = d2( d3 + d3( d4( + ) ) ) d1* 
        T1 = d1 d2 
        T2 = d3 d4 
        Waste = d1( d2( + d3( d4( + ) ) ) ) 

        # Transient Complexes 
        L1R1 = d1( d2 + d2( d3( + d3 d4( + ) ) ) ) 
        L1R2 = d1( d2 + d2( d3 + d3( d4( + ) ) ) ) 
        L2R1 = d1( d2( + d2 d3( + d3 d4( + ) ) ) ) 

        # Detailed Reactions 
        reaction [bind21         =      2.4e+06 /M/s ] C1 + T2 -> R1
        reaction [bind21         =      2.4e+06 /M/s ] L1 + T2 -> L1R1
        reaction [branch-3way    =      18.5185 /s   ] L1 -> L2
        reaction [branch-3way    =      18.5185 /s   ] L1R1 -> L1R2
        reaction [branch-3way    =      18.5185 /s   ] L1R1 -> L2R1
        reaction [branch-3way    =      18.5185 /s   ] L1R2 -> L1R1
        reaction [branch-3way    =      18.5185 /s   ] L1R2 -> Waste + Out
        reaction [bind21         =      2.4e+06 /M/s ] L2 + T2 -> L2R1
        reaction [branch-3way    =      18.5185 /s   ] L2 -> L1
        reaction [branch-3way    =      18.5185 /s   ] L2R1 -> L1R1
        reaction [branch-3way    =      18.5185 /s   ] L2R1 -> Waste + Out
        reaction [branch-3way    =      18.5185 /s   ] R1 -> R2
        reaction [branch-3way    =      18.5185 /s   ] R2 -> R1
        reaction [bind21         =      2.4e+06 /M/s ] T1 + C1 -> L1
        reaction [bind21         =      2.4e+06 /M/s ] T1 + R1 -> L1R1
        reaction [bind21         =      2.4e+06 /M/s ] T1 + R2 -> L1R2
        """)

        enum = Enumerator(complexes.values(), reactions)
        enum.k_fast = 0.01 
        enum.release_cutoff = 10
        enum.enumerate() # or enum.dry_run()

        enumRG = PepperCondensation(enum)
        enumRG.condense()
        
        """
        macrostate rC1 = [C1]
        macrostate rL2 = [L2, L1]
        macrostate rOut = [Out]
        macrostate rR1 = [R1, R2]
        macrostate rT1 = [T1]
        macrostate rT2 = [T2]
        macrostate rWaste = [Waste]

        reaction [condensed      =      2.4e+06 /M/s ] rT1 + rC1 -> rL2
        reaction [condensed      =      2.4e+06 /M/s ] rL2 + rT2 -> rWaste + rOut
        reaction [condensed      =      2.4e+06 /M/s ] rC1 + rT2 -> rR1
        reaction [condensed      =      2.4e+06 /M/s ] rT1 + rR1 -> rWaste + rOut
        reaction [condensed      =   0.00316623 /s   ] rL2 -> rT1 + rC1
        reaction [condensed      =   0.00316623 /s   ] rR1 -> rC1 + rT2
        """
        
        try:
            L1 = complexes['L1']
            L2 = complexes['L2']
            L = PepperMacrostate([L1, L2])
        except SingletonError as err:
            L = err.existing
        O = PepperMacrostate([complexes['Out']])
        W = PepperMacrostate([complexes['Waste']])
        T = PepperMacrostate([complexes['T2']])

        # calculated by hand...
        cr1 = PepperReaction([L, T], [W, O], 'condensed')
        assert cr1 in enumRG.condensed_reactions
        assert cr1.rate_constant == (2.4e6, '/M/s')