-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8d0e46f
commit 3f8589f
Showing
77 changed files
with
2,195 additions
and
0 deletions.
There are no files selected for viewing
Submodule 8-puzzle
added at
fb27a7
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
name: CPP project with GTest CI | ||
|
||
on: [push] | ||
|
||
jobs: | ||
build: | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v1 | ||
with: | ||
submodules: recursive | ||
- name: Prepare build dir | ||
run: mkdir build | ||
- name: Generate build files using cmake | ||
run: cmake .. | ||
working-directory: ./build | ||
- name: Run make | ||
run: make | ||
working-directory: ./build | ||
- name: Run tests | ||
timeout-minutes: 15 | ||
run: ./test/runUnitTests | ||
working-directory: ./build | ||
- name: Prepare ASAN build dir | ||
run: mkdir build_asan | ||
- name: Generate ASAN build files using cmake | ||
run: cmake .. -DCMAKE_BUILD_TYPE=ASAN | ||
working-directory: ./build_asan | ||
- name: Run make | ||
run: make | ||
working-directory: ./build_asan | ||
- name: Run tests | ||
timeout-minutes: 15 | ||
run: ./test/runUnitTests | ||
working-directory: ./build_asan | ||
- name: Prepare USAN build dir | ||
run: mkdir build_usan | ||
- name: Generate USAN build files using cmake | ||
run: cmake .. -DCMAKE_BUILD_TYPE=USAN | ||
working-directory: ./build_usan | ||
- name: Run make | ||
run: make | ||
working-directory: ./build_usan | ||
- name: Run tests | ||
timeout-minutes: 15 | ||
run: ./test/runUnitTests | ||
working-directory: ./build_usan |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Prerequisites | ||
*.d | ||
|
||
# Compiled Object files | ||
*.slo | ||
*.lo | ||
*.o | ||
*.obj | ||
|
||
# Precompiled Headers | ||
*.gch | ||
*.pch | ||
|
||
# Compiled Dynamic libraries | ||
*.so | ||
*.dylib | ||
*.dll | ||
|
||
# Fortran module files | ||
*.mod | ||
*.smod | ||
|
||
# Compiled Static libraries | ||
*.lai | ||
*.la | ||
*.a | ||
*.lib | ||
|
||
# Executables | ||
*.exe | ||
*.out | ||
*.app | ||
|
||
# ViM temporary files | ||
.*.swp | ||
|
||
CMakeCache.txt | ||
CMakeFiles/* | ||
CTestTestfile.cmake | ||
Makefile | ||
cmake_install.cmake |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[submodule "googletest"] | ||
path = googletest | ||
url = https://github.com/google/googletest.git | ||
[submodule "test"] | ||
path = test | ||
url = https://github.com/itiviti-cpp-master/genome-assembly-test.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
cmake_minimum_required(VERSION 3.13) | ||
|
||
include(test/Strict.cmake) | ||
|
||
set(PROJECT_NAME genome_assembly) | ||
project(${PROJECT_NAME}) | ||
|
||
# Set up the compiler flags | ||
set(CMAKE_CXX_FLAGS "-g") | ||
set(CMAKE_CXX_STANDARD 17) | ||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
|
||
# Inlcude directories | ||
set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}/include) | ||
include_directories(${COMMON_INCLUDES}) | ||
|
||
# Source files | ||
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp) | ||
|
||
# Separate executable: main | ||
list(REMOVE_ITEM SRC_FILES ${PROJECT_SOURCE_DIR}/src/main.cpp) | ||
|
||
# Compile source files into a library | ||
add_library(genome_assembly_lib ${SRC_FILES}) | ||
target_compile_options(genome_assembly_lib PUBLIC ${COMPILE_OPTS}) | ||
target_link_options(genome_assembly_lib PUBLIC ${LINK_OPTS}) | ||
|
||
# Main is separate | ||
add_executable(genome-assembly ${PROJECT_SOURCE_DIR}/src/main.cpp) | ||
target_compile_options(genome-assembly PRIVATE ${COMPILE_OPTS}) | ||
target_link_options(genome-assembly PRIVATE ${LINK_OPTS}) | ||
|
||
# linking Main against the library | ||
target_link_libraries(genome-assembly genome_assembly_lib) | ||
|
||
# google test is a git submodule | ||
add_subdirectory(googletest) | ||
|
||
enable_testing() | ||
|
||
# test is a git submodule | ||
add_subdirectory(test) | ||
|
||
add_test(NAME tests COMMAND runUnitTests) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# genome-assembly | ||
|
||
## Теоретическое введение | ||
|
||
Сборка генома - это вычислительный процесс, в котором определяется последовательность нуклеотидов составляющих геном организма. В настоящее время иследователи не могут прочитать последовательность нуклеотидов всей хромосомы. Вместо этого, они полагаются на высокотехнологичные химические методы, чтобы определить порядок нуклеобаз вдоль некой короткой части нити ДНК. Короткие фрагменты, полученные в результате, называются "reads". | ||
|
||
Чтобы опеределить геном, исследователи проводят данную химическую операцию несколько раз над несколькими копиями одного и того же генома, каждый раз получая некоторую короткую последовательность какой-то его части. Чтобы "собрать геном", они должны использовать пересечения в полученных строчках, чтобы понять какие последовательности примыкают друг к другу. Например, получив две короткие последовательности GGTG**ACC** и **ACC**TCGA, они могут заключить, что они обе относятся к подстроке GGTGACCTCGA. | ||
|
||
В общем случае неизвестно, каким образом пересекаются полученные фрагменты. К тому же, в ДНК две комплементарные нити и мы не знаем, с какой из них получен тот или иной фрагмент, и должны ли мы использовать его или его комплементарное отражение. Некоторую сложность привносит то, что современные методы чтения не идеальны и зачастую содержат ошибки. Также, некоторые регионы генома могут быть совсем не покрыты фрагментами. Однако, в нашей задаче мы возьмем упрощенный идеальный случай: мы будем считать, что наши фрагменты не содержат ошибок, получены с одной и той же нити ДНК, а также полностью покрывают геном. Причем мы точно знаем, размер пересекающихся частей фрагментов и то, что он одинаков для всех фрагментов. | ||
|
||
## Задача | ||
|
||
Разработать функцию, принимающую в качестве аргументов набор N строк одинаковой длины D в произвольном порядке, полученных в результате чтения, и натуральное число K (K < D) - длину пересекающихся концов фрагментов, возвращающую одну строку - геном, собранный из **всех** фрагментов. Гарантируется, что для всех входных данных такая строка существует и при том только одна. | ||
|
||
```c++ | ||
std::string assemble(size_t k, const std::vector<std::string> & fragments); | ||
``` | ||
Необходимо решить данную задачу, разбив входные фрагменты на все возможные подстроки размером (k + 1). Каждая такая подстрока будет соответсвовать переходу в направленном графе, где первой вершиной будет префикс размера k подстроки, а второй - суффикс размера k этой же подстроки. | ||
Например, для фрагмента ATCG и k = 2, подстроками будут ATC и TCG. Из первой подстроки получим две вершины и ребро: (AT) -> (TC), из второй: (TC) -> (CG). | ||
Повторив операцию для каждого исходного фрагмента, получим набор вершин и ребер. Склеив одинаковые вершины (но не склеивая ребра!), получим направленный граф, в котором присутсвует Эйлеров путь. Найдя этот путь, мы получим искомую строку - геном. | ||
## Пример решения | ||
Возьмем входные данные из первого примера ниже. | ||
K=2, [AATCT, ACGAA, GCTAC] | ||
1) Разобьем первый фрагмент на все возможные подстроки размером k + 1: AATCT -> AAT, ATC, TCT; | ||
2) Проделаем то же самое с остальными фрагментами: ACGAA -> ACG, CGA, GAA; GCTAC -> GCT, GTA, TAC; | ||
3) Каждая из полученных маленьких строк представляет собой переход в графе с вершинами из подстрок размером k. <br> | ||
AAT: (AA) -> (AT);<br> | ||
ATC: (AT) -> (TC);<br> | ||
TCT: (TC) -> (CT);<br> | ||
...<br> | ||
TAC: (TA) -> (AC);<br> | ||
4) Составим граф из получившихся переходов, склеив одинаковые вершины | ||
![Graph](https://user-images.githubusercontent.com/9121511/79051884-589fbe00-7c3b-11ea-88f3-26764afed4e6.png) | ||
5) Найдем путь Эйлера и используя его, составим искомую строку | ||
GC -> CT -> TA -> AC -> CG -> GA -> AA -> AT -> TC -> CT | ||
Для составления строки проведем операцию, обратную операции на шаге 3 для каждой пары последовательных вершин на пути.<br> | ||
GC -> CT: GCT<br> | ||
CT -> TA: CTA<br> | ||
TA -> AC: TAC<br> | ||
AC -> CG: ACG<br> | ||
CG -> GA: CGA<br> | ||
GA -> AA: GAA<br> | ||
AA -> AT: AAT<br> | ||
AT -> TC: ATC<br> | ||
TC -> CT: TCT<br> | ||
и наложим полученные фрагменты друг на друга в порядке, заданным путем: | ||
``` | ||
GCT | ||
CTA | ||
TAC | ||
ACG | ||
CGA | ||
GAA | ||
AAT | ||
ATC | ||
TCT | ||
GCTACGAATCT | ||
``` | ||
Искомая строка: GCTACGAATCT | ||
## Примеры | ||
Входные данные|Результат | ||
--------------|--------- | ||
K=2<br>AATCT<br>ACGAA<br>GCTAC | GCTACGAATCT | ||
K=3<br>AGCGDTA<br>DTACCCC<br>DTACTGG<br>TGGADTA | AGCGDTACTGGADTACCCC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
namespace genome | ||
{ | ||
|
||
std::string assembly(size_t k, const std::vector<std::string> &input); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#pragma once | ||
|
||
#include <list> | ||
#include <string_view> | ||
#include <set> | ||
#include <map> | ||
#include <vector> | ||
|
||
namespace genome { | ||
|
||
// one possible starting point | ||
// | ||
|
||
using Node = std::string_view; | ||
|
||
class Edge { | ||
public: | ||
Edge(Node from, Node to); | ||
|
||
const auto &from() const { return m_from; } | ||
|
||
const auto &to() const { return m_to; } | ||
|
||
bool operator==(const Edge &other) const; | ||
|
||
private: | ||
Node m_from; | ||
Node m_to; | ||
size_t m_id; | ||
static size_t id; | ||
}; | ||
|
||
class Graph { | ||
public: | ||
void add_edge(Edge edge); | ||
|
||
std::vector<Edge> find_euler_path(); | ||
|
||
private: | ||
std::map<Node, std::multiset<Node>> g; | ||
}; | ||
|
||
} // namespace genome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#include "genome.h" | ||
#include "graph.h" | ||
|
||
namespace genome { | ||
|
||
std::string generate_string(const std::vector<Edge> & euler_path) { | ||
std::string ans; | ||
ans = euler_path[0].from(); | ||
for (const auto & i : euler_path) { | ||
ans += i.to().back(); | ||
} | ||
return ans; | ||
} | ||
|
||
std::string assembly(size_t k, const std::vector<std::string> & input) { | ||
if (k == 0 || input.empty()) { | ||
return ""; | ||
} | ||
Graph g = Graph(); | ||
|
||
for (const auto &i : input) { | ||
std::string_view view(i); | ||
for (size_t j = 0; j + k < i.size(); j++) { | ||
std::string_view temp = view.substr(j, k + 1); | ||
g.add_edge(Edge(temp.substr(0, k), temp.substr(1, k))); | ||
} | ||
} | ||
return generate_string(g.find_euler_path()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#include "graph.h" | ||
#include <cmath> | ||
#include <stack> | ||
#include <vector> | ||
#include <algorithm> | ||
|
||
namespace genome { | ||
|
||
size_t Edge::id = 0; | ||
|
||
Edge::Edge(Node from, Node to) | ||
: m_from(from), m_to(to), m_id(id++) { | ||
} | ||
|
||
bool Edge::operator==(const Edge &other) const { | ||
return m_from == other.m_from && m_to == other.m_to && m_id == other.m_id; | ||
} | ||
|
||
void Graph::add_edge(Edge edge) { | ||
g[edge.from()].insert(edge.to()); | ||
} | ||
|
||
std::vector<Edge> Graph::find_euler_path() { | ||
std::map<Node, int> incoming; | ||
for (const auto & t : g) { | ||
for (const auto & node : t.second) { | ||
incoming[node]++; | ||
} | ||
} | ||
|
||
Node start_node; | ||
|
||
for (const auto & t : g) { | ||
if (t.second.size() - incoming[t.first] == 1) { | ||
start_node = t.first; | ||
break; | ||
} | ||
} | ||
|
||
std::stack<Node> stack; | ||
stack.push(start_node); | ||
std::vector<Node> nodes_on_path; | ||
|
||
while (!stack.empty()) { | ||
Node v = stack.top(); | ||
std::multiset<Node>& set = g[v]; | ||
if (!set.empty()) { | ||
stack.push(*set.begin()); | ||
set.erase(set.begin()); | ||
} else { | ||
nodes_on_path.emplace_back(v); | ||
stack.pop(); | ||
} | ||
} | ||
|
||
std::reverse(nodes_on_path.begin(), nodes_on_path.end()); | ||
|
||
std::vector<Edge> edge_path; | ||
|
||
for (size_t i = 0; i < nodes_on_path.size() - 1; ++i) { | ||
edge_path.emplace_back(nodes_on_path[i], nodes_on_path[i + 1]); | ||
} | ||
|
||
return edge_path; | ||
} | ||
|
||
} // namespace genome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#include "genome.h" | ||
|
||
#include <iostream> | ||
#include <string> | ||
#include <vector> | ||
|
||
int main() | ||
{ | ||
const std::vector<std::string> reads = {"AATCT", "ACGAA", "GCTAC"}; | ||
const std::size_t k = 2; | ||
std::cout << "K=" << k << ", ["; | ||
bool first = true; | ||
for (const auto & r : reads) { | ||
if (!first) { | ||
std::cout << ", "; | ||
} | ||
else { | ||
first = false; | ||
} | ||
std::cout << r; | ||
} | ||
std::cout << "]\n" << genome::assembly(k, reads) << std::endl; | ||
return 0; | ||
} |
Oops, something went wrong.