Вот если сместить учет пар на одно деление вправо, получим:
[‘A’, ‘GG’, ‘TG’, ‘AT’, ‘GG’, ‘A’]
Это то, о чем я говорил во втором вопросе. По идее уникальных делений на пары только два, так что может все таки можно как-то найти решение через этот способ?
Я тогда тоже поделюсь своими пока незаконченными рассуждениями. Можно разделить все нежелательные исходы на три группы, которые не пересекаются:
В последовательности нет G
Есть какое-то количество G, и все они находятся на расстоянии как минимум 1 буквы
Есть только одна ‘GG’, которая занимает только первые две позиции
Для первого и третьего случая посчитать нетрудно. В первом случае это просто 3^{100}, а в третьем — 3^{98}. Сейчас я пытаюсь понять, как можно найти число комбинаций для второго случая. Пробую посчитать это число для коротких последовательностей и потом вывести для общего случая, при длине в n букв.
А это прям красиво получилось. Я попытался продолжить твой ход, но пришел к еще одной проблеме. Мы не учитываем порядок пар. Он тоже может меняться. И казалось бы, что можно просто умножить на число перестановок этих 49 пар и 1 нуклеотида, но тогда вопрос — сколько таких перестановок?
У нас какие-то пары будут встречаться по несколько раз, такие варианты надо будет отсекать, но их количество зависит от того, какая пара повторяется и сколько раз она повторяется. Может получиться, что все 49 пар являются ‘AA’, а может получиться, что ‘AA’ повторяется 40 раз и ‘TT’ повторяется 9 раз. В каждом случае считать по-разному.
Вчера у меня стоял похожий вопрос и тогда я подумал, а что если через какое-то распределение выразить то, сколько будет какая-то пара повторяться? Тогда к каждому такому случаю можно было бы написать свое произведение, но это звучит как-то нереально, не могу даже представить, что там выйдет.
ED: я сейчас понял, что нам порядок и не важен, тогда все нормально
49 пар без ‘GG’. Потом 49-я пара либо имеет G на конце (тогда последним может быть любой из остальных трех), либо не имеет. И возвести в квадрат, потому что и при первом делении, и при втором, это все должно выполняться. А сами деления симметричны, поэтому можно взять одинаковые вероятности для них.
Во второй скобке поставил 15, потому что слева степень 49-я, значит уже все пары без ‘GG’, то есть выбирать осталось только среди 15 вариантов. 16 должно стоять если слева будет 48-я степень, мне кажется.
Если они одинаковые, то надо помножить на два, а не делить.
Не совсем понял откуда ты взял 12/15. Если продолжать мою мысль, то финальный ответ:
1-4\cdot k \cdot \frac{15}{16}^{49} \frac{51}{64}
Где k=1 или k=2 в зависимости от того перемножаем мы на два за счет другого деления или нет. На 4 множим т.к. первый нуклеотид (в последовательности из 100) может быть любым из четырех.
Откуда деление? Я возвел в квадрат, потому что это можно представить так: мы делим все на пары либо первым способом, либо вторым. Теперь они, вроде как, независимы. Нам надо, чтобы выполнялось “не” для обоих, поэтому надо их перемножить. Поскольку случаи симметричны, получилось возведение в квадрат.
Вероятность того, что последняя пара не заканчивается на G. Тогда последний нуклеотид может быть любым, то есть умножение на 1.
В 4 раза увеличится количество событий, как всех, так и нужных, поэтому я думаю, надо без умножения. И второй аргумент — две формулировки задачи эквивалентны.
Вот это самое интересное. Со вчерашнего дня у меня крутится мысль о том, чтобы написать код для симуляции. Можно написать функцию, которая рандомно выбирает букву из листа [‘A’, ‘T’, ‘G’, ‘C’], и ставит их подряд пока не получится 100 букв. Потом смотрит есть ли в этой строке ‘NGG’ и увеличивает счетчик нужных событий. Только есть опасения, что симуляция окажется слишком долгой.
В случае, когда последняя пара заканчивается на ‘G’, ты умножил на \frac{1}{4}, но надо было на \frac{3}{4}. И еще у меня в знаменателях стоит 15, а не 16, потому что в предыдущей скобке мы уже учли вероятность того, что все пары, включая последнюю, не являются ‘GG’. Тогда уже всего вариантов для последней пары не 16, а 15.
нам достаточно решить задачу “какова вероятность того, что в последовательности из 99 нуклеотидов не будет подряд идущих двух G”.
Давайте решим более общую задачу – какова вероятность того, что в последовательности из n нуклеотидов не будет подряд идущих двух G. Для этого найдем количество последовательностей из n нуклеотидов, таких, что в них нет GG, потом поделим на 4^n – на количество всех возможных последовательностей из n нуклеотидов. Так и получим вероятность.
Чтобы это найти, введем две вспомогательные функции: пусть f(n) – количество последовательностей длины n в которых нет GG и в которой последний нуклеотид G; g(n) – количество последовательностей длины n в которых нет GG и последний нуклеотид неG. Тогда ответом к нашей задаче будет число
\frac{f(99) + g(99)}{4^{99}}.
Попробуем найти рекуррентную зависимость этих двух функций.
С одной стороны, мы можем получить последовательность длины n которая не заканчивается на G, если к последовательности длины n-1 заканчивающееся на G припишем нуклеотид A,C,T (3 способа) или к последовательности длины n-1не заканчивающееся на G припишем нуклеотид A,C,T (3 способа). Следовательно
g(n) = 3\cdot g(n -1) + 3\cdot f(n - 1).
С другой стороны, мы можем получить последовательность длины n которая заканчивается на G, если к последовательности длины n-1не заканчивающееся на G припишем нуклеотид G (1 способ). Тогда имеем
f(n) = g(n - 1).
Соединим два равенства и распишем базовые случаи для n=1,n=2. Получаем
g(n) = 3g(n-1) + 3g(n-2), g(1) = 3, g(2) = 12.
Выпишем явную форму данного рекуррентного уравнения (можно сделать через характеристические уравнения, а можно через вольфрам). Получается вот такое несложное выражение
Получаю 0.9950793852734019 (официальное решение / то, что указала Балжан дает 0.999999245)
Дальше, я запустил Монте-Карло на задачу.
Cначала написал функцию проверки наличия фрагмента в последовательности
def isPresent(sequence, fragment):
'''
Inputs:
- sequence (str): a DNA sequence (or just a general string)
- fragment (str): two chars for which we perform the check
Output:
bool - whether el is present in sequence or not
'''
# TO DO: generalize function to general fragment???
last = None
for nucleotide in sequence:
if not last:
last = nucleotide
continue
if last + nucleotide == fragment:
return True
else:
last = nucleotide
return False
# SMAL DEBUG
# t1 = 'CATG'
# t2 = 'CGGT'
# t3 = 'CAGATGC'
# t4 = 'CAGATGG'
# for t in [t1, t2, t3, t4]:
# print(isPresent(t, 'GG'))
Дальше строим рандомную цепочку
import random
NUCLEOTIDES = ['A', 'G', 'C', 'T']
def build_sequence(elts, length):
'''
builds a string composed randomly from elts of given length
'''
seq = ''
for _ in range(length):
seq += random.choice(elts)
return seq
И наконец сама Монте Карло. Строим 1000 последовательностей десять раз:
def estimate_probability(length, elts, fragment, iterations):
'''
In N iterations, estimates probability that fragment is present in a random sequence of length made from elts
'''
fragmentPresent = 0
fragmentNotPresent = 0
for i in range(iterations):
print(f"building seq {i} / {iterations}")
randomSequence = build_sequence(elts, length)
if isPresent(randomSequence, fragment):
fragmentPresent += 1
else:
fragmentNotPresent += 1
return (fragmentPresent)/(fragmentPresent + fragmentNotPresent)
def average_probability(length, elts, fragment, iterations, runs):
'''
Perform N runs of estimate_probability
'''
return sum(probs:=[estimate_probability(length, elts, fragment, iterations) for _ in range(runs)])/len(probs)
length = 100
monteCarlo = average_probability(length, NUCLEOTIDES, 'GG', 1000, 10)
theory = theory.solve(length)
print(f"\n{monteCarlo} (MonteCarlo)\n{theory} (Theory)\n{theory-monteCarlo} (diff)\n")
Я запустил Монте Карло еще пару раз. Среднее значение вероятности получалось проводя 10 экспериментов, в которых создавалось N последовательностей ДНК, длиной в 100 нуклеотидов:
Думаю будет полезно пояснить откуда возникли эти страшные корни. На самом деле все просто и в процессе выведения явных решений линейных рекурсий нет ничего сложного.
Пусть нам дано рекуррентное соотношение
a_n = p\cdot a_{n-1} + q\cdot a_{n-2},
и известны значения a_1,a_2,p,q. Пусть x_1, x_2 – корни уравнения x^2 - px - q=0. Данное уравнение называется характеристическим уравнением рекуррентной последовательности. Тогда должны существовать такие A и B, что