예제 #1
0
def test_single_polymer_single_complex_instantiation():
    p = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    c1 = ComplexSpecies([p[0], p[1], Species("S")], called_from_complex=True)
    pc = PolymerConformation(complexes=[c1])
    #Test naming convention
    assert str(pc) == f"conformation__{p}_np0l0p0l1_{c1}_"

    p2 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m4")])
    c2 = ComplexSpecies([p[0], p2[0]], called_from_complex=True)

    #In these cases, TypeErrors should be raised
    with pytest.raises(ValueError):
        #Emtpy complexes is not allowed
        pc2 = PolymerConformation(complexes=[])

    with pytest.raises(ValueError):
        #set a PolymerConformation as a parent of the Species.
        S = Species("S")
        S.parent = pc
        c3 = ComplexSpecies([p[0], S], called_from_complex=True)
        pc2 = PolymerConformation(complexes=[c3])

    with pytest.raises(ValueError):
        #Cannot place an entire polymer into a Complex
        S = Species("S")
        S.parent = pc
        c3 = ComplexSpecies([p, S], called_from_complex=True)
        pc2 = PolymerConformation(complexes=[c3])
예제 #2
0
def test_complex_with_polymer_replacement():
    #These tests show how the order of binding can matter.
    #Best practices is to put everything into a PolymerConformation before doing Complex if PolymerConformations are being used.

    a = Species('A')
    b = Species('B')
    s = Species("S")
    p = OrderedPolymerSpecies([a, b, a])
    pc0 = PolymerConformation(
        polymer=p)  #Put the polymer inside a conformation
    #Bind two monomers together
    pc = Complex([pc0.polymers[0][0],
                  pc0.polymers[0][1]]).parent  #get a PolymerConformation

    assert isinstance(pc, PolymerConformation)

    #create a Complex around an unbound element of p (from within pc)
    c = Complex([s, pc.polymers[0][2], s], ordered=True)
    assert str(c) == str(
        OrderedComplexSpecies([s, p[2], s], called_from_complex=True))
    assert str(pc.polymers[0]) == str(c.parent.polymers[0])
    assert len(c.parent.complexes) > len(pc.complexes)

    #Make the same thing with the replacement first
    #this gives a different final complex than doing things in the previous order
    p2 = OrderedPolymerSpecies([a, b, Complex([s, a, s], ordered=True)])
    pc2 = PolymerConformation(polymer=p2)
    assert str(c.parent) != str(p2)
    assert c.parent.parent != Complex([pc2.polymers[0][0], pc2.polymers[0][1]
                                       ]).parent
예제 #3
0
def test_get_complex():
    p = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    c1 = ComplexSpecies([p[0], p[1], Species("S")], called_from_complex=True)
    pc = PolymerConformation(complexes=[c1])

    assert str(pc.get_complex(c1)) == str(
        c1
    )  #these are not technically equal because they have different parents
예제 #4
0
def test_complex_with_single_polymer():
    a = Species('A')
    b = Species('B')
    p = OrderedPolymerSpecies([a, b, a])

    #This should just produce a ComplexSpecies around the PolymerSpecies
    c2 = Complex([p, Species("S")])
    assert c2 == ComplexSpecies([p, Species("S")], called_from_complex=True)

    #If the Polymer is in a Conformation, it cannot be Complexed.
    pc = PolymerConformation(polymer=p)
    assert str(pc.polymers[0]) == str(p)
    assert pc.polymers[0].parent == pc
    assert p.parent is None

    with pytest.raises(ValueError):
        c2 = Complex([pc.polymers[0], Species("S")])

    #A monomer form the polymer can still be complexed, however
    c2 = Complex([pc.polymers[0][0], Species("S")])
    assert isinstance(c2.parent, PolymerConformation)
    assert c2.parent != pc
    assert len(c2.parent.complexes) == 1
    assert len(c2.parent.polymers) == 1
    assert str(c2) == str(
        ComplexSpecies([pc.polymers[0][0], Species("S")],
                       called_from_complex=True))
예제 #5
0
def test_complex_with_a_complex_in_a_conformation():
    #This occurs when Complexes are formed around Complexes in PolymerConformations.
    #In these cases, the Complexes are merged to prevent nested Complexes inside of PolymerConformations.
    #Using ordered = True to test that order is preserved
    a = Species('A')
    b = Species('B')
    c = Species('C')
    p = OrderedPolymerSpecies([a, b, c])
    pc0 = PolymerConformation(polymer=p)
    pc = Complex([pc0.polymers[0][0], pc0.polymers[0][1]],
                 ordered=True).parent  #get a PolymerConformation
    c = pc.complexes[0]  #get a complex from the PolymerConformation

    c2 = Complex([c, Species("S")],
                 ordered=True)  #Create a Complex with a Complex
    pc2 = c2.parent
    assert str(c2) == str(OrderedComplexSpecies([p[0], p[1],
                                                 Species("S")
                                                 ]))  #merging done correctly
    assert pc2 == Complex(
        [pc0.polymers[0][0], pc0.polymers[0][1],
         Species("S")],
        ordered=True).parent  #check the parent PolymerConformation
    assert len(pc2.complexes) == 1

    #Create a PolymerConformation with two complexes
    c3 = Complex([pc2.polymers[0][0], pc2.polymers[0][2],
                  Species("S2")],
                 ordered=True)
    pc3 = c3.parent
    assert len(pc3.complexes) == 2
    assert str(c3) == str(
        OrderedComplexSpecies([p[0], p[2], Species("S2")],
                              called_from_complex=True))

    #merge the two complexes in pc3
    c4 = Complex([pc3.complexes[0], pc3.complexes[1],
                  Species("S3")],
                 ordered=True)
    assert len(c4.parent.complexes) == 1
    assert str(c4) == str(
        Complex([
            pc0.polymers[0][0], pc0.polymers[0][1],
            Species("S"), pc0.polymers[0][0], pc0.polymers[0][2],
            Species("S2"),
            Species("S3")
        ],
                ordered=True))
    assert c4.parent == Complex([
        pc0.polymers[0][0], pc0.polymers[0][1],
        Species("S"), pc0.polymers[0][0], pc0.polymers[0][2],
        Species("S2"),
        Species("S3")
    ],
                                ordered=True).parent
예제 #6
0
def test_polymer_conformation_no_complex_instantiation():
    p = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    pc = PolymerConformation(polymer=p)
    c1 = ComplexSpecies([p[0], p[1], Species("S")], called_from_complex=True)

    assert str(pc) == str(p)  #these should have the same name!
    assert str(p) == str(pc.polymers[0])
    assert len(pc.complexes) == 0

    pc2 = PolymerConformation(
        polymer=[Species("m1"), Species("m2"),
                 Species("m3")])
    assert pc2 == pc

    with pytest.raises(ValueError):
        pc = PolymerConformation(polymer=["A", None])

    with pytest.raises(NotImplementedError):
        pc = PolymerConformation(polymer=[p, p])

    with pytest.raises(ValueError):
        pc = PolymerConformation(polymer=p, complexes=[c1])

    with pytest.raises(ValueError):
        pc = PolymerConformation()
예제 #7
0
def test_complex_with_multiple_polymers():
    a = Species('A')
    b = Species('B')
    p = OrderedPolymerSpecies([a, b, a])
    pc0 = PolymerConformation(polymer=p)
    p2 = OrderedPolymerSpecies([b, a, b])
    pc2 = PolymerConformation(polymer=p2)

    #Bind one two monomers from one polymer
    #Polymers must be placed into a Conformation before being bound together
    with pytest.raises(TypeError):
        c = Complex([Species("S"), p[0], p[2]])

    c = Complex([Species("S"), pc0.polymers[0][0], pc0.polymers[0][2]])

    #Correct parent
    assert c.parent == PolymerConformation(
        [ComplexSpecies([Species("S"), p[0], p[2]], called_from_complex=True)])
    #correct complex returned
    assert str(c) == str(
        ComplexSpecies([Species("S"), p[0], p[2]], called_from_complex=True))

    #Ordered Case
    oc = Complex([Species("S"), pc0.polymers[0][0], pc0.polymers[0][2]],
                 ordered=True)
    #Correct parent
    assert oc.parent == PolymerConformation([
        OrderedComplexSpecies([Species("S"), p[0], p[2]],
                              called_from_complex=True)
    ])
    #correct complex returned
    assert str(oc) == str(
        OrderedComplexSpecies([Species("S"), p[0], p[2]],
                              called_from_complex=True))

    #Two polymers which bind together
    #Polymers must be placed into a Conformation before being bound together
    with pytest.raises(TypeError):
        c2 = Complex([Species("S"), p[0], p2[1]])

    c2 = Complex([Species("S"), pc0.polymers[0][0], pc2.polymers[0][1]])
    assert c2.parent == PolymerConformation([
        ComplexSpecies([Species("S"), p[0], p2[1]], called_from_complex=True)
    ])
    assert str(c2) == str(
        ComplexSpecies([Species("S"), p[0], p2[1]], called_from_complex=True))

    #Two polymers already bound together in a Conformation interacting at a new location
    l1 = c2.parent.polymers[0][1]
    l2 = c2.parent.polymers[1][0]
    c3 = Complex([l1, l2], ordered=True)
    assert c3.parent == PolymerConformation([
        ComplexSpecies([Species("S"), p[0], p2[1]], called_from_complex=True),
        OrderedComplexSpecies([p[1], p2[0]], called_from_complex=True)
    ])
    assert str(c3) == str(
        OrderedComplexSpecies([p[1], p2[0]], called_from_complex=True))
예제 #8
0
def test_degenerate_polymer_conformation():
    S = Species("S")
    p = OrderedPolymerSpecies([S, S, S])
    pc = PolymerConformation(polymer=p)

    c1 = Complex([pc.polymers[0][0], pc.polymers[0][1]])
    pc1 = c1.parent

    c2 = Complex([pc.polymers[0][1], pc.polymers[0][2]])
    pc2 = c2.parent

    c3 = Complex([pc.polymers[0][0], pc.polymers[0][2]])
    pc3 = c3.parent

    assert pc1 != pc2 != pc3
예제 #9
0
def test_multiple_polymer_multiple_complex_instantiation():
    p1 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    p2 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m4")])

    c1 = ComplexSpecies([p1[0], p1[1]], called_from_complex=True)
    c2 = ComplexSpecies([p1[0], p2[2]], called_from_complex=True)
    c3 = ComplexSpecies([Species("S1"), Species("S2")],
                        called_from_complex=True)

    pc1 = PolymerConformation(complexes=[c1, c2])

    #Check naming convention
    assert str(pc1) == f"conformation__{p1}_{p2}_p0l0p0l1_{c1}_p0l0p1l2_{c2}_"

    #check that order doesn't matter
    pc1_r = PolymerConformation(complexes=[c2, c1])
    assert pc1 == pc1_r

    #check that ComplexSpecies with the same string representation but different polymers are treated differently
    c1b = ComplexSpecies(
        [p2[1], p1[0]], called_from_complex=True
    )  #c1 and c1b have the same string representation - but connect different polymers
    pc1b = PolymerConformation(complexes=[c1b, c2])
    assert str(pc1b) == f"conformation__{p1}_{p2}_p0l0p1l1_{c1}_p0l0p1l2_{c2}_"
    assert pc1 != pc1b

    #Check that order doesn't matter for Complexes with the same string representation
    pc1br = PolymerConformation(complexes=[c2, c1b])  #reverse case
    assert pc1b == pc1br

    pc2 = PolymerConformation(complexes=[c1, c2])
    pc2b = PolymerConformation(complexes=[c1b, c2])
    assert pc2 != pc2b

    #In these cases, value errors should be raised
    with pytest.raises(ValueError):
        #c3 is not part of the conformation
        pc = PolymerConformation(complexes=[c1, c3])

    #try 2 polymers with complexes that look the same
    p3 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    c4 = ComplexSpecies([p1[0], p3[0]])

    pc3 = PolymerConformation([c1, c4])
    assert str(pc3) == f"conformation__{p1}_{p1}_p0l0p0l1_{c1}_p0l0p1l0_{c4}_"

    #check that order doesn't matter for polymers which look the same
    pc3r = PolymerConformation([c4, c1])
    assert pc3 == pc3r

    with pytest.raises(ValueError):
        #duplicate Complexes are not allowed (same object case)
        pc4 = PolymerConformation([c1, c1])

    c1b = ComplexSpecies([p1[0], p1[1]], called_from_complex=True)
    with pytest.raises(ValueError):
        #duplicate Complexes are not allowed (identical object case)
        pc4 = PolymerConformation([c1, c1b])
예제 #10
0
def test_polymer_conformation_ordered_polymer_species_name_equality():
    p = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    pc = PolymerConformation(polymer=p)
    assert str(p) == str(pc)
예제 #11
0
def test_from_polymer_replacement():
    #tests the classmethod .from_polymer_replacement

    #Produce a PolymerConformation
    p1 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    c1 = ComplexSpecies(
        [p1[0], p1[1], Species("S"), Species("S")], called_from_complex=True)
    pc1 = PolymerConformation(complexes=[c1])

    #Produce a second Polymer
    p2 = OrderedPolymerSpecies([Species("m3"), Species("m2"), Species("m1")])
    #replace p1 with p2
    pc1_replaced = PolymerConformation.from_polymer_replacement(
        pc1, [pc1.polymers[0]], [p2])

    #This should be equivalent to creating a new PolymerConformation
    c2 = ComplexSpecies(
        [p2[0], p2[1], Species("S"), Species("S")], called_from_complex=True)
    pc2 = PolymerConformation(complexes=[c2])
    assert pc1_replaced == pc2

    #Replacing a Polymer with the same polymer is valid, but doesn't do anything
    pc1_replaced_b = PolymerConformation.from_polymer_replacement(
        pc1, [pc1.polymers[0]], [p1])
    assert pc1_replaced_b == pc1

    #These conditions should raise ValueErrors
    with pytest.raises(TypeError):
        PolymerConformation.from_polymer_replacement(pc1, [pc1.polymers[0]],
                                                     None)

    with pytest.raises(ValueError):
        PolymerConformation.from_polymer_replacement(pc1, [None], [p2])

    with pytest.raises(TypeError):
        PolymerConformation.from_polymer_replacement(pc1, [pc1.polymers[0]],
                                                     [None])

    with pytest.raises(ValueError):
        PolymerConformation.from_polymer_replacement(pc1, [p1], [p2])

    with pytest.raises(ValueError):
        PolymerConformation.from_polymer_replacement(pc1, [pc1.polymers[0]],
                                                     [p1, p2])

    with pytest.raises(TypeError):
        PolymerConformation.from_polymer_replacement(None, [pc1.polymers[0]],
                                                     [p1, p2])
예제 #12
0
def test_from_polymer_conformation():
    #tests the classmethod .from_polymer_conformation

    #Produce a PolymerConformation
    p1 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    c1 = ComplexSpecies([p1[0], p1[1]], called_from_complex=True)
    pc1 = PolymerConformation(complexes=[c1])

    #This Complex uses the polymer inside the pc1 so there is only a single polymer in the final PolymerConformation
    c1b = ComplexSpecies([pc1.polymers[0][0], pc1.polymers[0][2]],
                         called_from_complex=True)
    c1bb = ComplexSpecies([p1[0], p1[2]])
    pc1b = PolymerConformation.from_polymer_conformation([pc1], [c1b])

    #This is correct (and checking ordering effects don't matter)
    assert pc1b == PolymerConformation([c1, c1bb]) == PolymerConformation(
        [c1bb, c1])

    #This is incorrect because of polymers being copied into conformations
    assert pc1b != PolymerConformation([c1, c1b])

    #This Complex uses the old Polymer Instance which will represent the binding to a new, identical, PolymerSpecies
    #all three of the following therefore should be the same
    c1c = ComplexSpecies([p1[0], p1[2]], called_from_complex=True)
    pc1c = PolymerConformation.from_polymer_conformation([pc1], [c1c])

    p1d = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m3")])
    c1d = ComplexSpecies([p1d[0], p1d[2]], called_from_complex=True)
    pc1d = PolymerConformation.from_polymer_conformation([pc1], [c1c])

    #Create directly
    pc1e = PolymerConformation([c1d, c1])
    pc1er = PolymerConformation([c1, c1d])  #Order shouldn't matter

    assert pc1c == pc1d == pc1e == pc1er

    #Test from multiple PolymerConformations
    p2 = OrderedPolymerSpecies([Species("m1"), Species("m2"), Species("m4")])
    c2 = ComplexSpecies([p2[0], p2[1]], called_from_complex=True)
    pc2 = PolymerConformation(complexes=[c2])
    #Create a PolymerConformation that links the two Polymers together
    c3 = ComplexSpecies([p1[0], p1[1]], called_from_complex=True)
    pc3 = PolymerConformation([c3])

    #Add an additional binding site connecting pc2 and pc3
    c4 = ComplexSpecies([pc3.polymers[0][0], pc2.polymers[0][1]
                         ])  #get the conformations polymers due to copying
    pc4 = PolymerConformation.from_polymer_conformation([pc2, pc3], [c4])
    c4b = ComplexSpecies([p1[0], p2[1]])

    assert pc4 == PolymerConformation([c2, c3, c4b]) == PolymerConformation(
        [c4b, c2, c3])  #And order doesn't matter
    assert pc4 != PolymerConformation(
        [c2, c3, c4])  #This should be different due to copying

    #The following should produce errors
    with pytest.raises(TypeError):
        pc1b = PolymerConformation.from_polymer_conformation(pc1, [c1b])
    with pytest.raises(TypeError):
        pc1b = PolymerConformation.from_polymer_conformation([c1b], [c1b])
def test_CombinatorialConformation_init():

    #Test getters and setters of properties via init

    X, Y, Z = Species("X"), Species("Y"), Species("Z")
    C = Complex([X, X])
    p1 = OrderedPolymerSpecies([X, Y, Z])
    pc0 = PolymerConformation(polymer=p1)
    pc1 = Complex([pc0.polymers[0][0], pc0.polymers[0][2]
                   ]).parent  #this gets the PolymerConformation

    CC1 = CombinatorialConformation(initial_states=[pc0], final_states=[pc1])

    assert len(CC1.initial_states) == 1 and len(CC1.final_states) == 1

    pc1b = Complex([pc0.polymers[0][2], Z]).parent
    CC1b = CombinatorialConformation(initial_states=[pc0], final_states=[pc1b])
    assert len(CC1.initial_states) == 1 and len(CC1.final_states) == 1

    pc1c = Complex([pc1b.polymers[0][0], pc1b.polymers[0][1]]).parent
    CC1c0 = CombinatorialConformation(initial_states=None,
                                      final_states=[pc1b, pc1c])
    assert len(CC1c0.final_states) == 2
    assert len(CC1c0.initial_states) == 1
    CC1c1 = CombinatorialConformation(initial_states=[pc0, pc1b],
                                      final_states=[pc1c])
    assert len(CC1c1.initial_states) == 2

    #The following should produce errors:
    p2 = OrderedPolymerSpecies([Z, Y, X])
    pc2 = Complex(
        [pc1.polymers[0][1],
         PolymerConformation(polymer=p2).polymers[0][1]]).parent
    with pytest.raises(ValueError):  #Multiple internal polymers
        CC = CombinatorialConformation(initial_states=[pc1],
                                       final_states=[pc2])

    with pytest.raises(ValueError):  #Multiple internal polymers
        CC = CombinatorialConformation(initial_states=[pc0, pc1],
                                       final_states=[pc2])

    with pytest.raises(ValueError):  #Multiple internal polymers
        CC = CombinatorialConformation(initial_states=[pc0],
                                       final_states=[pc1],
                                       intermediate_states=[pc2])
    with pytest.raises(ValueError):  #Multiple internal polymers
        CC = CombinatorialConformation(initial_states=[pc0],
                                       final_states=[pc2],
                                       excluded_states=[pc1])
    with pytest.raises(ValueError):  #Multiple internal polymers
        CC = CombinatorialConformation(initial_states=[pc0],
                                       final_states=[pc1],
                                       excluded_states=[pc2])

    #Non PolymerConformations passed as initial/final/intermediate states
    with pytest.raises(ValueError):
        CC = CombinatorialConformation(initial_states=[C], final_states=[pc1])

    with pytest.raises(ValueError):
        CC = CombinatorialConformation(initial_states=[pc0], final_states=[C])

    with pytest.raises(ValueError):
        CC = CombinatorialConformation(initial_states=[pc0],
                                       final_states=[pc1],
                                       intermediate_states=[C])

    with pytest.raises(ValueError):
        CC = CombinatorialConformation(initial_states=[pc0],
                                       final_states=[pc1],
                                       excluded_states=[C])
def test_update_species_and_reactions():
    params = {"kf": 1, "kr": 1}

    X, Y, Z, S = Species("X"), Species("Y"), Species("Z"), Species("S")
    C = Complex([X, X])
    p0 = OrderedPolymerSpecies([X, Y, Z, C])
    pc0 = PolymerConformation(polymer=p0)
    c1 = Complex([pc0.polymers[0][0], pc0.polymers[0][1]])
    pc1 = c1.parent
    c2 = Complex(
        [pc0.polymers[0][0], pc0.polymers[0][1], pc0.polymers[0][2], S, S])
    pc2 = c2.parent
    c3 = Complex([pc1.polymers[0][2], pc1.polymers[0][3], Z])
    pc3 = c3.parent
    c4 = Complex([
        pc0.polymers[0][0], pc0.polymers[0][1], pc0.polymers[0][2],
        pc0.polymers[0][3], Z
    ])
    pc4 = c4.parent

    #No conformation changes are possible
    CC0 = CombinatorialConformation(initial_states=[],
                                    final_states=[pc0],
                                    parameters=params)
    species = CC0.update_species()
    reactions = CC0.update_reactions()
    assert len(species) == 0
    assert len(reactions) == 0

    #Only a single binding reaction can occur
    CC1 = CombinatorialConformation(initial_states=[],
                                    final_states=[pc1],
                                    parameters=params)
    species = CC1.update_species()
    reactions = CC1.update_reactions()
    assert len(species) == 2
    assert pc1 in species and pc0 in species
    assert len(reactions) == 1

    #This should be the same as above, by default
    CC1b = CombinatorialConformation(initial_states=[pc0],
                                     final_states=[pc1],
                                     parameters=params)
    species = CC1b.update_species()
    reactions = CC1b.update_reactions()
    assert len(species) == 2
    assert pc1 in species and pc0 in species
    assert len(reactions) == 1

    #Test multiple final states
    CC2 = CombinatorialConformation(initial_states=[pc0],
                                    final_states=[pc1, pc2],
                                    parameters=params)
    species = CC2.update_species()
    reactions = CC2.update_reactions()
    assert len(species) == 4
    assert pc1 in species and pc0 in species and pc2 in species and S in species
    assert len(reactions) == 2

    #Test multiple pathways
    CC3 = CombinatorialConformation(initial_states=[pc0],
                                    final_states=[pc3],
                                    parameters=params)
    species = CC3.update_species()
    reactions = CC3.update_reactions()
    assert len(species) == 5
    assert pc1 in species and pc0 in species and pc3 in species and Z in species
    assert len(reactions) == 4

    #Test intermediate states
    CC3b = CombinatorialConformation(initial_states=[pc0],
                                     intermediate_states=[pc1],
                                     final_states=[pc3],
                                     parameters=params)
    species = CC3b.update_species()
    reactions = CC3b.update_reactions()
    assert len(species) == 4
    assert pc1 in species and pc0 in species and pc1 in species and Z in species and pc3 in species
    assert len(reactions) == 2

    #Test excluded intermediate states
    CC3c = CombinatorialConformation(initial_states=[pc0],
                                     excluded_states=[pc1],
                                     final_states=[pc3],
                                     parameters=params)
    species = CC3c.update_species()
    reactions = CC3c.update_reactions()
    assert len(species) == 4
    assert pc0 in species and pc1 not in species and Z in species and pc3 in species
    assert len(reactions) == 2

    #Test adding a dead end intermediate species
    CC3c = CombinatorialConformation(initial_states=[pc0],
                                     intermediate_states=[pc1, pc2],
                                     final_states=[pc3],
                                     parameters=params)
    species = CC3c.update_species()
    reactions = CC3c.update_reactions()
    assert len(species) == 6
    assert pc0 in species and pc1 in species and Z in species and pc3 in species and pc2 in species and S in species
    assert len(reactions) == 3

    #Test expanding a pathway through intermediates
    CC4a = CombinatorialConformation(initial_states=[pc0],
                                     final_states=[pc4],
                                     parameters=params)
    species = CC4a.update_species()
    reactions = CC4a.update_reactions()
    assert len(species) == 3
    assert pc0 in species and pc4 in species
    assert len(reactions) == 1

    CC4b = CombinatorialConformation(initial_states=[pc0],
                                     intermediate_states=[pc3],
                                     final_states=[pc4],
                                     parameters=params)
    species = CC4b.update_species()
    reactions = CC4b.update_reactions()
    assert len(species) == 6
    assert pc0 in species and pc4 in species and pc1 in species and pc3 in species
    assert len(reactions) == 5
def test_get_combinations_between():
    X, Y, Z, S = Species("X"), Species("Y"), Species("Z"), Species("S")
    C = Complex([X, X])
    p0 = OrderedPolymerSpecies([X, Y, Z, C])
    pc0 = PolymerConformation(polymer=p0)
    c1 = Complex([pc0.polymers[0][0], pc0.polymers[0][1]])
    pc1 = c1.parent
    c2 = Complex(
        [pc0.polymers[0][0], pc0.polymers[0][1], pc0.polymers[0][2], S, S])
    pc2 = c2.parent
    c3 = Complex([pc1.polymers[0][2], pc1.polymers[0][3], Z])
    pc3 = c3.parent
    c4 = Complex([
        pc0.polymers[0][0], pc0.polymers[0][1], pc0.polymers[0][2],
        pc0.polymers[0][3], Z
    ])
    pc4 = c4.parent
    c5a = Complex([pc0.polymers[0][0], pc0.polymers[0][2]])
    pc5a = c5a.parent
    c5b = Complex([pc5a.polymers[0][1], pc5a.polymers[0][3]])
    pc5b = c5b.parent

    print("pc0", pc0, "\npc1", pc1, "\npc2", pc2, "\npc3", pc3, "\npc4", pc4)

    #Arguments here don't matter in this test
    CC = CombinatorialConformation(initial_states=[],
                                   intermediate_states=[],
                                   final_states=[pc3])

    #No additional species added
    perms = CC.get_combinations_between(s0=pc0, sf=pc1)
    assert len(perms) == 1

    #External Species added
    perms = CC.get_combinations_between(s0=pc0, sf=pc2)
    assert len(perms) == 1

    #Multiple Complexes created
    perms = CC.get_combinations_between(s0=pc0, sf=pc3)
    assert len(perms) == 4

    #A single complex created, from a conformation with complexes
    perms = CC.get_combinations_between(s0=pc1, sf=pc3)
    assert len(perms) == 1

    #Adding species to an existing Complex
    perms = CC.get_combinations_between(s0=pc1, sf=pc2)
    assert len(perms) == 1

    #adding species (including inside the polymer) to an existing complex
    perms = CC.get_combinations_between(s0=pc1, sf=pc4)
    assert len(perms) == 1

    #merging two complexes
    perms = CC.get_combinations_between(s0=pc3, sf=pc4)
    assert len(perms) == 1

    #Adding an excluded_state
    #excluded_state matters here
    CC = CombinatorialConformation(initial_states=[],
                                   excluded_states=[pc1],
                                   final_states=[pc3])
    perms = CC.get_combinations_between(s0=pc0, sf=pc3)
    assert len(perms) == 2

    #Cases where compute_species_changes should return False
    #s0 contains more species/complexes than sf
    assert len(CC.get_combinations_between(s0=pc3, sf=pc0)) == 0
    assert len(CC.get_combinations_between(s0=pc3, sf=pc1)) == 0
    assert len(CC.get_combinations_between(s0=pc2, sf=pc1)) == 0
    assert len(CC.get_combinations_between(s0=pc2, sf=pc3)) == 0
    assert len(CC.get_combinations_between(s0=pc3, sf=pc2)) == 0
    #Partially overlapping sets of monomers are bound
    assert len(CC.get_combinations_between(s0=pc3, sf=pc5a)) == 0
    assert len(CC.get_combinations_between(s0=pc5a, sf=pc3)) == 0
    #These ones are especially tricky because the same Monomers are bound, but in different sets of complexes
    assert len(CC.get_combinations_between(s0=pc3, sf=pc5b)) == 0
    assert len(CC.get_combinations_between(s0=pc5b, sf=pc3)) == 0
def test_compute_species_changes():
    X, Y, Z, S = Species("X"), Species("Y"), Species("Z"), Species("S")
    C = Complex([X, X])
    p0 = OrderedPolymerSpecies([X, Y, Z, C])
    pc0 = PolymerConformation(polymer=p0)
    c1 = Complex([pc0.polymers[0][0], pc0.polymers[0][1]])
    pc1 = c1.parent
    ind_c1 = pc1.get_polymer_positions(c1, 0)
    c2 = Complex(
        [pc0.polymers[0][0], pc0.polymers[0][1], pc0.polymers[0][2], S, S])
    pc2 = c2.parent
    ind_c2 = pc2.get_polymer_positions(c2, 0)
    c3 = Complex([pc1.polymers[0][2], pc1.polymers[0][3], Z])
    pc3 = c3.parent
    ind_c3 = pc3.get_polymer_positions(c3, 0)
    c4 = Complex([
        pc0.polymers[0][0], pc0.polymers[0][1], pc0.polymers[0][2],
        pc0.polymers[0][3], Z
    ])
    pc4 = c4.parent
    ind_c4 = pc4.get_polymer_positions(c4, 0)

    print("pc0", pc0, "\npc1", pc1, "\npc2", pc2, "\npc3", pc3, "\npc4", pc4)

    CC = CombinatorialConformation(initial_states=[pc0],
                                   intermediate_states=[pc1],
                                   final_states=[pc2, pc3])

    #No additional species added
    SC, MC = CC.compute_species_changes(s0=pc0, sf=pc1)
    assert (c1, ind_c1) in SC
    assert len(SC[(c1, ind_c1)]) == 0
    assert (c1, ind_c1) in MC
    assert len(MC[(c1, ind_c1)]) == 0

    #External Species added
    SC, MC = CC.compute_species_changes(s0=pc0, sf=pc2)
    assert (c2, ind_c2) in SC
    assert len(SC[(c2, ind_c2)]) == 2 and S in SC[(c2, ind_c2)]
    assert all([len(MC[cf]) == 0 for cf in MC])

    #Multiple Complexes created
    SC, MC = CC.compute_species_changes(s0=pc0, sf=pc3)
    assert (pc3.complexes[0], ind_c1) in SC and (pc3.complexes[1],
                                                 ind_c3) in SC
    assert len(SC[pc3.complexes[0], ind_c1]) == 0
    assert len(SC[pc3.complexes[1], ind_c3]) == 1 and Z in SC[pc3.complexes[1],
                                                              ind_c3]
    assert all([len(MC[cf]) == 0 for cf in MC])

    #A single complex created, from a conformation with complexes
    SC, MC = CC.compute_species_changes(s0=pc1, sf=pc3)
    assert (pc3.complexes[0], ind_c1) not in SC and (pc3.complexes[1],
                                                     ind_c3) in SC
    assert len(SC[pc3.complexes[1], ind_c3]) == 1 and Z in SC[pc3.complexes[1],
                                                              ind_c3]
    assert len(MC[pc3.complexes[1], ind_c3]) == 0

    #Adding species to an existing Complex
    SC, MC = CC.compute_species_changes(s0=pc1, sf=pc2)
    assert (pc1.complexes[0], ind_c1) not in SC and (pc2.complexes[0],
                                                     ind_c2) in SC
    assert len(SC[pc2.complexes[0], ind_c2]) == 2 and S in SC[pc2.complexes[0],
                                                              ind_c2]
    assert pc1.complexes[0] in MC[pc2.complexes[0], ind_c2]

    #adding species (including inside the polymer) to an existing complex
    SC, MC = CC.compute_species_changes(s0=pc1, sf=pc4)
    assert (pc1.complexes[0], ind_c1) not in SC and (pc4.complexes[0],
                                                     ind_c4) in SC
    assert Z in SC[pc4.complexes[0], ind_c4] and len(SC[pc4.complexes[0],
                                                        ind_c4]) == 1
    assert pc1.complexes[0] in MC[pc4.complexes[0], ind_c4]

    #merging two complexes
    SC, MC = CC.compute_species_changes(s0=pc3, sf=pc4)
    assert (pc3.complexes[0],
            ind_c1) not in SC and (pc3.complexes[1],
                                   ind_c3) not in SC and (pc4.complexes[0],
                                                          ind_c4) not in SC
    assert pc3.complexes[0] in MC[
        pc4.complexes[0], ind_c4] and pc3.complexes[1] in MC[pc4.complexes[0],
                                                             ind_c4]

    #Cases where compute_species_changes should return False

    #No changes between the conformations
    assert not CC.compute_species_changes(s0=pc0, sf=pc0)

    #because s0 contains more species/complexes than sf
    assert not CC.compute_species_changes(s0=pc3, sf=pc0)
    assert not CC.compute_species_changes(s0=pc3, sf=pc1)
    assert not CC.compute_species_changes(s0=pc2, sf=pc1)
    assert not CC.compute_species_changes(s0=pc2, sf=pc3)
    assert not CC.compute_species_changes(s0=pc3, sf=pc2)