def threshold_bottom_strand(input_: int, gate: int) -> nc.Strand:
    """Returns a threshold bottom strand for seesaw gate labeled `gate` that
    thresholds `input`

    .. code-block:: none

     s{input}* T*      ss{gate}*   s{gate}*
         |     |          |        |
        [==--=====--=============--==>

    :param input_: Name of input that is being thresholded
    :type input_: int
    :param gate: Name of gate
    :type gate: int
    :return: Threshold bottom strand
    :rtype: dc.Strand
    """
    # Note, this assumes that this input signal domain has already been built
    d_input_sub = recognition_domains_and_subdomains[f's{input_}']
    d_gate = get_signal_domain(gate)

    s: nc.Strand = nc.Strand(domains=[d_input_sub, TOEHOLD_DOMAIN, d_gate],
                             starred_domain_indices=[0, 1, 2],
                             name=f'threshold_bottom_{input_}_{gate}')
    return s
def signal_strand(gate3p: Union[int, str], gate5p: Union[int,
                                                         str]) -> nc.Strand:
    """Returns a signal strand with recognition domains
    gate3p and gate5p on the 3' and 5' respectively

    .. code-block:: none

                S{g3p}                       S{g5p}
          ss{g3p}      s{g3p}  T       ss{g5p}    s{g5p}
            |           |     |          |         |
        <=============--==--=====--=============--==]

    :param gate3p: Gate to be identified by the recognition domain on the 3'
                   end
    :type gate3p: Union[int, str]
    :param gate5p: Gate to be identified by the recognition domain on the 5'
                   end
    :type gate5p: Union[int, str]
    :return: Strand
    :rtype: dc.Strand
    """
    d3p = get_signal_domain(gate3p)
    d5p = get_signal_domain(gate5p)

    name = f'signal_{gate3p}_{gate5p}'
    return nc.Strand(domains=[d5p, TOEHOLD_DOMAIN, d3p],
                     starred_domain_indices=[],
                     name=name)
def main():
    domain_length = 15
    # energy_constraint = dc.NearestNeighborEnergyConstraint(low_energy=-9.2, high_energy=-7)
    numpy_constraints = [  # energy_constraint,
        nc.RunsOfBasesConstraint(['C', 'G'], 4),
        nc.RunsOfBasesConstraint(['A', 'T'], 4)
    ]
    domain_pool = nc.DomainPool(f'length-{domain_length} domains', domain_length,
                                numpy_constraints=numpy_constraints, replace_with_close_sequences=True)

    random_seed = 0
    strands = [nc.Strand([f'{i}' for i in range(1, 50)])]
    for strand in strands:
        for domain in strand.domains:
            domain.pool = domain_pool
    params = ns.SearchParameters(
        constraints=[nc.nupack_strand_complex_free_energy_constraint(
            threshold=-1.5, temperature=52, short_description='StrandSS', parallel=False)],
        out_directory='output/hamming_dist_test',
        # weigh_violations_equally=True
        report_only_violations=False,
        random_seed=random_seed,
        max_iterations=None)
    params.force_overwrite = True  # directly deletes output folder contents w/o user input
    # params.report_delay = 0.0

    design = nc.Design(strands)
    ns.search_for_dna_sequences(design, params)
def reporter_bottom_strand(gate) -> nc.Strand:
    """Returns a reporter bottom strand for seesaw gate labeled `gate`

    .. code-block:: none

           T*     ss{gate}*   s{gate}*
           |          |        |
        [=====--=============--==>

    :param gate: Name of gate
    :type gate: [type]
    :return: Reporter bottom strand
    :rtype: dc.Strand
    """
    s: nc.Strand = nc.Strand(domains=[TOEHOLD_DOMAIN,
                                      get_signal_domain(gate)],
                             starred_domain_indices=[0, 1],
                             name=f'reporter_bottom_{gate}')
    return s
def reporter_top_strand(gate: int) -> nc.Strand:
    """Returns a waste strand for a reporting reaction involving
    the seesaw gate labeled `gate`

    .. code-block:: none

            ss{gate}   s{gate}
               |        |
        <=============--==]

    :param gate: Name of gate
    :type gate: int
    :return: Waste strand
    :rtype: dc.Strand
    """
    s: nc.Strand = nc.Strand(domains=[get_signal_domain(gate)],
                             starred_domain_indices=[],
                             name=f'reporter_top_{gate}')
    return s
def gate_base_strand(gate: int) -> nc.Strand:
    """Returns a gate base strand with recognition domain `gate`.

    .. code-block:: none
                        S{gate}*
           T*      ss{gate}* s{gate}* T*
           |          |        |      |
        [=====--=============--==--=====>

    :param gate: Gate to be identified by the recognition domain
    :type gate: int
    :return: Gate base strand
    :rtype: dc.Strand
    """
    d = get_signal_domain(gate)
    s: nc.Strand = nc.Strand(domains=[TOEHOLD_DOMAIN, d, TOEHOLD_DOMAIN],
                             starred_domain_indices=[0, 1, 2],
                             name=f'gate_base_{gate}')
    return s
def fuel_strand(gate: int) -> nc.Strand:
    """Returns a fuel strand with recognition domain `gate`.

    .. code-block:: none

         ss{gate}    s{gate}  T         ssf        sf
            |           |     |          |         |
        <=============--==--=====--=============--==]

    :param gate: The name of the gate that this fuel strand will fuel.
    :type gate: int
    :return: Fuel strand
    :rtype: dc.Strand
    """
    d3p = get_signal_domain(gate)
    fuel = FUEL_DOMAIN

    name = f'fuel_{gate}'
    return nc.Strand(domains=[fuel, TOEHOLD_DOMAIN, d3p],
                     starred_domain_indices=[],
                     name=name)