СиАОД_1-4.docx
.pdf
Вывод
Реализовали генерацию фрактала «Дерево Пифагора» с применением рекурсивных функций. Из результатов тестов сделали вывод, что
«Дерево Пифагора» несложный фрактал на низких глубинах, и становится сложнее с большими глубинами.
41
задание 4 Поиск подстроки в строке
Цель работы
Реализовать заданный метод поиска подстроки в строке в соответствии с индивидуальным заданием. Для всех вариантов добавить реализацию добавления строк, ввода подстроки и поиска подстроки. Предусмотреть возможность существования пробела. Ввести опцию чувствительности / нечувствительности к регистру. Оценить время работы каждого алгоритма поиска и сравнить его со временем работы стандартной функции поиска, используемой в выбранном языке программирования.
Вариант 18
Метод Кнута Морриса Пратта
Ход работы
В ходе выполнения напишем реализацию Метода поиска подстроки в строке
std::vector<std::size_t> KMP(const std::string &text, const std::string &pattern) {
std::vector<std::size_t> res; int m = text.length();
int pattern_length = pattern.length(); // if pattern is an empty string
if (pattern_length == 0) {
std::cout << "The pattern occurs with shift 0"; return res;
}
// if text's length is less than that of pattern's if (m < pattern_length) {
std::cout << "Pattern not found"; return res;
}
42
//next[i] stores the index of the next best partial match std::vector<int> next(pattern_length + 1, 0);
//Preprocessing the pattern to calculate the LPS (Longest Prefix Suffix)
//array
for (int i = 1, len = 0; i < pattern_length;) { if (pattern[i] == pattern[len]) {
next[i++] = ++len;
}else if (len > 0) { len = next[len - 1];
}else { next[i++] = 0;
}
}
// Searching the pattern in the text using the LPS array for (int i = 0, j = 0; i < m;) {
if (text[i] == pattern[j]) { i++;
j++;
if (j == pattern_length) { res.push_back(i - j);
j = next[j - 1]; // Continue searching for next match
}
}else if (j > 0) { j = next[j - 1];
}else { i++;
}
}
return res;
}
#if 0
Для сравнения возьмем алгоритм стандартной библиотеки языка C++ libstdc++
43
int countOccurrences(const std::vector<unsigned char> &data, const std::string &pattern) {
int count = 0;
std::string dataStr(data.begin(), data.end());
std::size_t pos = dataStr.find(pattern); while (pos != std::string::npos) {
count++;
pos = dataStr.find(pattern, pos + pattern.length());
}
return count;
}
а также алгоритм для решения задачи k-nucleotide (приводить его не буду)
https://benchmarksgame-team.pages.debian.net/benchmarksgame/description/knucl eotide.html#knucleotide
https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/knuc leotide.html
Для проверки работы нашего алгоритма, придумаем задачу приближенную к реальности, а также же такую на которой КМП должен давать более хорошие результаты по сравнению с другими методами.
с сайта: https://www.ncbi.nlm.nih.gov/
были загружены секвенированные геномы 5 (184.1) MB и 11 (58.2 MB) хромосом. 5 хромосома 11 миллионов пар оснований
были установлены праймеры гена рецептора дофамина в 11 хромосоме https://www.jstage.jst.go.jp/article/jes/13/2/13_2_57/_pdf
44
например : (декодированный пример, праймерный участок выделен цветом)
>lcl|NC_000011.10_cds_NP_000788.2_142 [gene=DRD4] [db_xref=CCDS:CCDS7710.1,Ensembl:ENSP00000176183.5,GeneID:1815] [protein=D(4) dopamine receptor] [protein_id=NP_000788.2] [location=join(637305..637589,639433..639545,639648..640306,640401..640603)] [gbkey=CDS]
ATGGGGAACCGCAGCACCGCGGACGCGGACGGGCTGCTGGCTGGGCGC GGGCCGGCCGCGGGGGCATCTGCGGGGGCATCTGCGGGGCTGGCTGGGC AGGGCGCGGCGGCGCTGGTGGGGGGCGTGCTGCTCATCGGCGCGGTGCT CGCGGGGAACTCGCTCGTGTGCGTGAGCGTGGCCACCGAGCGCGCCCTG CAGACGCCCACCAACTCCTTCATCGTGAGCCTGGCGGCCGCCGACCTCCT CCTCGCTCTCCTGGTGCTGCCGCTCTTCGTCTACTCCGAGGTCCAGGGTG GCGCGTGGCTGCTGAGCCCCCGCCTGTGCGACGCCCTCATGGCCATGGA CGTCATGCTGTGCACCGCCTCCATCTTCAACCTGTGCGCCATCAGCGTGG ACAGGTTCGTGGCCGTGGCCGTGCCGCTGCGCTACAACCGGCAGGGTGG GAGCCGCCGGCAGCTGCTGCTCATCGGCGCCACGTGGCTGCTGTCCGCG GCGGTGGCGGCGCCCGTACTGTGCGGCCTCAACGACGTGCGCGGCCGCG ACCCCGCCGTGTGCCGCCTGGAGGACCGCGACTACGTGGTCTACTCGTCC GTGTGCTCCTTCTTCCTACCCTGCCCGCTCATGCTGCTGCTCTACTGGG CCACGTTCCGCGGCCTGCAGCGCTGGGAGGTGGCACGTCGCGCCAAGCT GCACGGCCGCGCGCCCCGCCGACCCAGCGGCCCTGGCCCGCCTTCCCCC ACGCCACCCGCGCCCCGCCTCCCCCAGGACCCCTGCGGCCCCGACTGTG CGCCCCCCGCGCCCGGCCTTCCCCGGGGTCCCTGCGGCCCCGACTGTGC GCCCGCCGCGCCCAGCCTCCCCCAGGACCCCTGCGGCCCCGACTGTGCG CCCCCCGCGCCCGGCCTCCCCCCGGACCCCTGCGGCTCCAACTGTGCTCC CCCCGACGCCGTCAGAGCCGCCGCGCTCCCACCCCAGACTCCACCGCAG ACCCGCAGGAGGCGGCGTGCCAAGATCACCGGCCGGGAGCGCAAGGCC ATGAGGGTCCTGCCGGTGGTGGTCGGGGCCTTCCTGCTGTGCTGGACGC CCTTCTTCGTGGTGCACATCACGCAGGCGCTGTGTCCTGCCTGCTCCGTG CCCCCGCGGCTGGTCAGCGCCGTCACCTGGCTGGGCTACGTCAACAGCG CCCTCAACCCCGTCATCTACACTGTCTTCAACGCCGAGTTCCGCAACGTC TTCCGCAAGGCCCTGCGTGCCTGCTGCTGA
были установлены праймеры гена рецептора адреналина в 5 хромосоме https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5859892/
Праймеры для ПЦР — это короткие фрагменты одноцепочечной ДНК, обычно около 20 нуклеотидов в длину. В каждой реакции ПЦР используются два праймера, и они сконструированы так, чтобы фланкировать целевой участок
45
(который необходимо скопировать). Таким образом, праймеры представляют собой последовательности, которые связываются с цепями матричной ДНК точно по краям копируемой области. Праймеры связываются с матрицей, образуя пары комплементарных оснований.
В нашем случае Праймер будет использоваться как способ уникальной идентификации наличия гена.
Итак приступим, общая схема тестирования.
timer.start();
int occurrences = countOccurrences(data, pattern); timer.stop();
std::cout << "The pattern '" << pattern << "' occurs " << occurrences
<<" times in the input data." << timer.elapsedMicrosec() << " microseconds
"<< std::endl;
libstdc++ find algorithm
Компилируем простой поиск :
46
компиляция :
g++ src/main.cpp -std=c++17 -march=native -msse -msse2 -msse3 -O3 -o simple_find
ищем дофамин в геноме 11 хромосомы
./simple_find -p CCGCTCATGCTGCTGCTCTACTGG < sequence_11_full.fasta
The pattern 'CCGCTCATGCTGCTGCTCTACTGG' occurs 1 times in the input data: 100109 microseconds
можем проверить что данный паттерн не встречается в другой хромосоме
./simple_find -p CCGCTCATGCTGCTGCTCTACTGG < sequence_5chomosome_full.fasta
The pattern 'CCGCTCATGCTGCTGCTCTACTGG' occurs 0 times in the input data: 296673 microseconds (время больше так как данных больше)
попробуем поискать рецепторы адреналина
./simple_find -p AGGCAGCTCCAGAAGATTG < sequence_11_full.fasta
The pattern 'AGGCAGCTCCAGAAGATTG' occurs 0 times in the input data: 129443 microseconds
в 11 хромосоме праймер не найден
/simple_find -p AGGCAGCTCCAGAAGATTG < sequence_5chomosome_full.fasta
The pattern 'AGGCAGCTCCAGAAGATTG' occurs 1 times in the input data: 413622 microseconds
найден 1 праймер в 11 хромосоме.
The Knute Morris Pratt search method find :
Компиляция :
g++ src/kmp.cpp -O3 -o kmp_find
ищем дофамин в геноме 11 хромосомы
./kmp_find -p CCGCTCATGCTGCTGCTCTACTGG < sequence_11_full.fasta
The pattern 'CCGCTCATGCTGCTGCTCTACTGG' occurs 1 times in the input data: 180918 microseconds
47
Проверяем что этого праймера нет в другой хромосоме
./kmp_find -p CCGCTCATGCTGCTGCTCTACTGG < sequence_5chomosome_full.fasta
The pattern 'CCGCTCATGCTGCTGCTCTACTGG' occurs 0 times in the input data: 571367 microseconds
праймера рецептора адреналина не найдено в 11 хрмосоме
./kmp_find -p AGGCAGCTCCAGAAGATTG < sequence_11_full.fasta
The pattern 'AGGCAGCTCCAGAAGATTG' occurs 0 times in the input data: 271423 microseconds
праймер найден в 5 хромосоме :
./kmp_find -p AGGCAGCTCCAGAAGATTG < sequence_5chomosome_full.fasta
The pattern 'AGGCAGCTCCAGAAGATTG' occurs 1 times in the input data: 887541 microseconds
Замеры времени
метод |
размер |
найден |
мкс |
прим |
поиска |
файла |
о |
|
|
|
MB |
|
|
|
|
|
|
|
|
48
libstdc++ |
58 |
1 |
100109 |
ген рецептора дофамина в 11 хромосоме |
|
|
|
|
DRD4 праймер |
kmp |
58 |
1 |
180918 |
CCGCTCATGCTGCTGCTCTACTGG |
|
|
|
|
|
libstdc++ |
184 |
0 |
296673 |
тот же праймерный участок но в другой |
|
|
|
|
хромосоме. |
kmp |
184 |
0 |
571367 |
|
|
|
|
|
|
libstdc++ |
184 |
1 |
413622 |
ген ADRB2 рецептора адреналина в 5 |
|
|
|
|
хромосоме |
kmp |
184 |
1 |
887541 |
|
|
|
|
|
|
libstdc++ |
58 |
0 |
129443 |
ген ADRB2 рецептора адреналина в 11 |
|
|
|
|
хромосоме |
kmp |
58 |
0 |
271423 |
|
|
|
|
|
|
Выводы
Реализовали заданный метод поиска подстроки в строке в соответствии с индивидуальным заданием. Оценили время работы алгоритма поиска и сравнили его со временем работы стандартной функции поиска, используемой в выбранном языке программирования. И в результате получилось, что встроенный алгоритм получился немного быстрее, чем реализованный. И, скорее всего, при увеличении строки, в которой будет осуществляться поиск, разница в скорости поиска будет увеличиваться, и наилучший результат будет показывать встроенный алгоритм поиска, т.к они спроектированы для производительности в больших объемах.
Список Литературы
1. Ахо Альфред В. Структуры данных и алгоритмы:
2. Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ.
49
3. Кнут Д.Э. Искусство программирования: в 4-x томах. 4. Тим Рафгаден Algorithms Illuminated в 4 х томах
5. Andrii Gakhov probabilistic data structures and algorithms for big data applications
6. Thomas Mailund The Joys of Hashing
7. Stepanov, Alexander; Kershenbaum, Aaron Using Tournament Trees to Sort
8. Determination and Variability of Nucleotide Sequences for D4 Dopamine Receptor Genes (DRD4) in Genus Equus
9. www.geeksforgeeks.org
10.www.ncbi.nlm.nih.gov
50
