Thuật toán tìm giao của các đoạn gen sử dụng cây quản lí đoạn

Một phần của tài liệu (LUẬN văn THẠC sĩ) cây quản lí đoạn và ứng dụng (Trang 36)

Ta sẽ xem xét một phương pháp nhanh chóng và linh hoạt để tìm giao giữa các đoạn gen bằng cách sử dụng cây quản lí đoạn.

Việc tìm các đoạn gen giao nhau gồm hai bước: (hình 2.5)

 Xây dựng cây quản lí đoạn từ tập dữ liệu thứ nhất (chèn từng đoạn gen vào cây)

 Thực hiện truy vấn với mỗi đoạn gen trong tệp thứ hai.

Cách làm này có độ phức tạp tính toán trung bình là O(nlgn) cho thao tác dựng cây và O(mlgn) cho tất cả các truy vấn, suy ra độ phức tạp của toàn bộ chương trình là O(nlgn + mlgn). Để tránh trường hợp tệ nhất khi cây quản lí đoạn là cây nhị phân suy biến, cần triển khai cài đặt cây quản lí đoạn bằng một cây nhị phân tìm kiếm tự cân bằng.

Nhập dữ liệu hệ gene Xây dựng rừng IT từ tập dữ liệu hệ gene Tìm giao của đoạn gene g trên rừng IT Thông báo kết quả tìm kiếm Nhập đoạn gene cần tìm giao g

Hình 2.5. Các bước tìm giao của một đoạn gen với các đoạn gen trong một hệ gen

Có thể mô tả cụ thể thuật toán tìm giao các đoạn gen như sau:

Dữ liệu vào: hai tập các đoạn gen, mỗi đoạn gen biểu diễn bởi tên nhiễm sắc thể, vị trí đầu đoạn gen và vị trí cuối đoạn gen.

Kết quả ra: các đoạn gen có giao với nhau trong cùng nhiễm sắc thể và vị trí của các đoạn gen giao nhau đó; số lượng các đoạn gen giao nhau.

Bƣớc 1: xây dựng rừng gồm các cây quản lí đoạn từ tập các đoạn gen thứ nhất. Bước này bản chất là tổ chức lưu trữ dữ liệu chuẩn bị cho việc tìm kiếm ở bước 2.

Bƣớc 2: với mỗi đoạn trong tập thứ hai, tìm các đoạn giao của nó với các đoạn trong rừng các cây quản lí đoạn đã xây dựng được.

2.4.1. Xây dựng rừng cây quản lí đoạn lƣu trữ thông tin các đoạn gen

Từ tệp dữ liệu thứ nhất lưu thông tin về các đoạn gen, ta sẽ xây dựng được một rừng các cây quản lí đoạn. Mỗi cây quản lí đoạn thể hiện một số đoạn gen của cùng một nhiễm sắc thể. Mỗi nút trên cây mô tả tương ứng một đoạn gen. Cấu trúc một nút trên cây gồm:

chromName: tên nhiễm sắc thể chứa đoạn gen đang xét.

chromStart, chromEnd: vị trí đầu đoạn gen, cuối đoạn gen trong

nhiễm sắc thể.

maxhigh: giá trị lớn nhất của các vị trí cuối đoạn (đầu mút phải) của

các đoạn nằm trong nhánh cây gốc p, được tính theo công thức truy

hồi: p ^ .left ^ .maxhigh p ^ .maxhigh max p ^ . f p ^ .right ^ .maxhigh      

minlow: giá trị bé nhất của các vị trí đầu đoạn (đầu mút trái) của các

đoạn nưm trong nhánh cây gốc p. Thuộc tính này có thể có hoặc

không, để tiện trong các tính toán, nó được tính đệ quy tương tự như

maxhigh.

left, right: con trỏ trỏ tới nút con trái và nút con phải của p.

Các nút có thuộc tính chromName giống nhau thì cùng thuộc một cây quản lí đoạn (cùng nằm trên một nhiễm sắc thể). Do đó, ánh xạ mỗi tên nhiễm sắc thể thành một số nguyên dương duy nhất đánh số từ 0, mỗi số tương ứng cho chỉ số một cây quản lí đoạn. Tổ chức dữ liệu cần thiết cho bài toán như sau:

Type

pnode = ^node; node = record

chromStart, chromEnd: longint; maxhigh: longint;

left, right: pnode; end;

var chr: array[0..100000] of pnode;

Chẳng hạn, thông tin về các đoạn gen của nhiễm sắc thể số 1, có tên chr1, sẽ được lưu trong cây quản lí đoạn quản lí bởi nút gốc chr[1], từ nút gốc đi theo các hướng liên kết left, right ta có thể duyệt mọi nút khác trên cây.

Cấu trúc nút của cây quản lí đoạn lưu trữ thông tin đoạn gen được minh họa như ở hình 2.6.

[110, 1650] 1650 [10, 750] 750 [840, 900] 1120 [45, 122] 122 [220, 780] 780 [921, 1120] 1120 nil

nil nil nil nil

chromStart = 840 chromStart = 840 chromEnd = 900 chromEnd = 900 maxhigh = 1120 maxhigh = 1120 left left right right

Hình 2.6. Cấu trúc nút và cây quản lí đoạn lưu thông tin các đoạn gen của một nhiễm sắc thể

Chi tiết bƣớc 1: duyệt các đoạn gen của tập thứ nhất, với mỗi đoạn, tìm cây quản lí đoạn của cùng nhiễm sắc thể này, sau đó chèn đoạn đó vào cây tìm được.

for each đoạn iti do

Tìm cây Tj quản lí các đoạn của NST iti.ChromeName

Chèn đoạn iti vào cây Tj;

end for

Thao tác tìm cây Tj quản lí các đoạn của nhiễm sắc thể có tên

iti.ChromeName là việc ánh xạ tương ứng từ xâu kí tự lưu tên sang số nguyên

làm chỉ số của cây:

//nCh là số nhiễm sắc thể khác nhau hay là số cây //StrCh là mảng kiểu xâu lưu danh sách tên các NST For j:=0 to nCh-1 do

If iti.ChromeName = strCh[j] then return j; //Trường hợp không tìm được j thì bổ sung cây mới j := j + 1;

Việc chèn đoạn iti có giá trị [iti.chromStart, iti.chromEnd] vào cây Tj có thể được thực hiện bằng thao tác đệ quy insertIT:

 Nếu cây rỗng thì tạo nút mới chứa đoạn [iti.chromStart, iti.chromEnd] và cho nút này làm gốc của cây.

 Nếu nút T có T^.s > iti.chromStart thì ta tìm chỗ chèn ở cây con trái,

ngược lại thì chèn đoạn vào cây con phải.

 Nếu trên cây đã có nút quản lí thông tin đoạn iti thì không chèn thêm đoạn này lên cây nữa.

 Cập nhật T^.rightmost := iti.chromEnd nếu T^.rightmost < iti.chromEnd.

Thời gian tìm kiếm trung bình phụ thuộc vào chiều cao của cây, là O(lgn) trong trường hợp cây gần hoàn chỉnh. Tuy nhiên, để tránh tình trạng cây nhị phân suy biến, cây có n nút có chiều cao h = n, cây quản lí đoạn trong trường hợp này cần được thiết kế là một cây nhị phân tìm kiếm tự cân bằng, ví dụ như cây đỏ đen [2] (hình 2.6). Đây là một cấu trúc phức tạp nhưng cho kết quả tốt về thời gian trong trường hợp xấu nhất.

Trong cây đỏ đen, các nút không có con được gọi là lá và được gán giả là nil, nghĩa là chúng không chứa bất kì dữ liệu nào. Tại đây nó sẽ chịu trách nhiệm thông báo rằng cây đã kết thúc. Việc thêm các nút này làm cho tất cả các nút trong của cây đều chứa dữ liệu và có hai con, hay khác đi, cây đỏ đen cùng với các lá nil là cây nhị phân đầy đủ. Cây đỏ đen cũng giống như các cây nhị phân tìm kiếm khác đều thỏa mãn tính chất: mỗi nút được gán một giá trị sao cho giá trị trên mỗi nút nhỏ hơn hoặc bằng tất cả các giá trị trên các nút thuộc cây con phải và lớn hơn các giá trị nằm trên cây con trái. Điều đó làm cho quá trình tìm kiếm nhanh hơn. Vận dụng cây đỏ đen cho trường hợp cây quản lí đoạn, mỗi nút quản lí thông tin một đoạn sao cho khi duyệt cây theo thứ tự giữa ta được dãy giá trị tăng dần theo đầu mút trái của mỗi đoạn; tức là

giá trị đầu mút trái của mỗi đoạn trên mỗi nút nhỏ hơn hoặc bằng tất cả các giá trị đầu mút trái của các đoạn nằm trên cây con phải và lớn hơn các giá trị đầu mút trái của các đoạn được quản lí trên cây con trái.

Mỗi nút của cây đỏ đen chứa thêm một bit màu (đỏ hoặc đen). Ngoài các tính chất của cây nhị phân tìm kiếm, cây đỏ đen thỏa mãn tính chất sau đây:

 Mọi nút đều được tô màu (đỏ hoặc đen);

 Nút gốc có màu đen;

 Nút nil có màu đen;

 Nếu một nút được tô màu đỏ thì cả hai nút con của nút đó được tô màu đen;

 Với mỗi nút, tất cả các đường đi từ nút đó đến các nút lá hậu duệ có cùng một số lượng nút đen. Tính chất này còn được gọi là tính chất "cân bằng đen". Số các nút đen trên một đường đi từ gốc tới mỗi lá được gọi là độ dài đen của đường đi đó. Ở đây ta chỉ xét các đường đi từ gốc tới các lá nên ta sẽ gọi tắt các đường đi như vậy là đường đi. Sức mạnh của cây đỏ đen nằm trong các tính chất trên. Từ các tính chất này suy ra trong các đường đi từ gốc tới các lá, đường đi dài nhất không vượt quá hai lần đường đi ngắn nhất do số các nút đen trên hai đường đi đó bằng nhau. Do đó cây đỏ đen là gần cân bằng. Vì các thuật toán chèn, tìm kiếm trong trường hợp xấu nhất đều tỷ lệ với chiều cao của cây nên cây đỏ đen rất hiệu quả trong các trường hợp xấu nhất không giống như cây nhị phân tìm kiếm thông thường. Khi đó, thao tác chèn một nút (một đoạn gen) vào cây sẽ là thao tác tô màu và cân bằng cây. Vì chiều cao của cây đỏ đen có n nút

không vượt quá 2lg(n + 1), suy ra độ phức tạp của thao tác chèn một nút lên cây khi cài đặt cây quản lí đoạn bằng cây đỏ đen là O(lgn).

Gọi n, m là số đoạn gen trong tập dữ liệu thứ nhất, thứ hai. Không mất

tính tổng quát, giả sử n > m. Thời gian để tạo rừng cây quản lí đoạn từ dữ liệu tập các đoạn gen là O(nlgn).

2.4.2. Tìm kiếm các đoạn gen giao nhau

Chi tiết bƣớc 2: với mỗi đoạn trong tệp thứ hai, tìm các đoạn gen trong rừng các cây quản lí đoạn đã xây dựng được có giao với nó.

for each <đoạn iti> do

Tìm cây Tj quản lí các đoạn của NST iti.ChromeName

Liệt kê các đoạn giao của iti với Tj; //listIntervals end for

Trong trường hợp bài toán con, chỉ thực hiện riêng lẻ từng truy vấn trong cửa sổ truy vấn đối với đoạn gen g, bước này có thể bỏ vòng lặp duyệt tất cả các đoạn bên ngoài:

Tìm cây Tj quản lí các đoạn của NST iti.ChromeName

Liệt kê các đoạn giao của g với Tj; //listIntervals

Việc tìm cây Tj lưu thông tin của nhiễm sắc thể iti.chromName là việc

duyệt qua danh sách tên các nhiễm sắc thể để ánh xạ tìm ra chỉ số j tương ứng như đã trình bày ở bước 1.

Khi đó, ta có thể viết lại thủ tục listIntervals như sau:

Procedure listIntervals(p: pnode; a, b: real); Begin

If p = nil then return;

If p^.left^.maxhigh>= a then

listIntervals(p^.left, a, b);

if overlapped(p^.chromStart, p^.chromEnd, a, b) then Output [p^.chromStart, p^.chromEnd];//Liệt kê If p^.chromStart<=b then

listIntervals(p^.right, a, b); End;

Bước này được thao tác bằng lời gọi thủ tục listIntervals(Tj, iti.chromStart, iti.chromEnd) hay listIntervals(Tj, g.chromStart, g.chromEnd)

cho trường hợp cửa sổ truy vấn.

Độ phức tạp giải thuật của bước này là O(lgn) cho một truy vấn và là O(mlgn) cho tất cả truy vấn.

Độ phức tạp thuật toán là O(nlgn + mlgn).

Như đã phân tích, cây quản lí đoạn rất thuận tiện và phù hợp khi thiết kế các cửa sổ truy vấn hay trong các bài toán truy vấn phạm vi. Thông thường cấu trúc dữ liệu cây quản lí đoạn được sử dụng trong trường hợp này thì việc xây dựng cây quản lí đoạn có độ phức tạp lớn hơn truy vấn. Một khi cây quản lí đoạn đã xây dựng xong, chúng ta có thể thực hiện truy vấn tìm kiếm nhanh chóng. Điều này rất có lợi với một môi trường dạng cơ sở dữ liệu, nhất là khi dữ liệu vào là một hệ gen chứa rất nhiều thông tin. Khi đó ta sẽ xây dựng rừng cây quản lí đoạn ngay từ ban đầu, sau đó thực hiện các truy vấn trong suốt phần còn lại của ứng dụng. Điều này cũng rất hợp lí khi sử dụng cây quản lí đoạn để thiết kế cửa sổ truy vấn giải quyết bài toán tìm giao của một đoạn gen với tập các đoạn gen.

Tóm lại, chương này đã đưa ra hai thuật toán tìm giao các đoạn gen. Trong đó, trình bày chi tiết về cấu trúc dữ liệu cây quản lí đoạn và áp dụng nó để xây dựng thuật toán tìm giao hai tập các đoạn gen và đánh giá độ phức tạp của thuật toán đưa ra.

Chƣơng 3.

MÃ HÓA, THỬ NGHIỆM CHƢƠNG TRÌNH TÌM GIAO CÁC ĐOẠN GEN

3.1. Chuẩn bị dữ liệu

Hiện nay, cơ sở dữ liệu về tin sinh học được lưu trữ rất nhiều trên các ngân hàng cơ sở dữ liệu như: DDBJ, GenBank, EMBL, NCBI-Unigen, TRANSFAC, EBI,v.v… , đây là những kho dữ liệu khổng lồ được cập nhật hàng ngày và miễn phí đối với tất cả mọi người trên thế giới. Luận văn sử dụng ngân hàng cơ sở dữ liệu của UCSC [12], dữ liệu về các hệ gen ở định dạng BED [11]. BED là một cách linh hoạt thể hiện các đặc điểm, chú giải gen và các đoạn gen, truy cập cũng nhanh hơn, thay vì các cơ sở dữ liệu phức tạp khác. BED mô tả hơn 12 thuộc tính của hệ gen, tuy nhiên trong bài toán này ta chỉ quan tâm tới 3 thuộc tính sau:

1. chromName: là một xâu kí tự biểu diễn tên nhiễm sắc thể (Ví dụ: chr3, chrY, chr2_random, scaffold10671,...).

2. chromStart: là số nguyên chỉ ra vị trí bắt đầu của đoạn gen trong nhiễm sắc thể (đánh số bắt đầu từ 0).

3. chromEnd: là số nguyên cho biết vị trí kết thúc của đoạn gen trong nhiễm sắc thể.

Các thuộc tính ngăn cách nhau bởi khoảng trống. Thí dụ: chr19 11823 14433

Mô tả: đoạn gen nằm ở nhiễm sắc thể chr19, từ vị trí 11823 đến vị trí 14433.

Hình 3.1 là giao diện trang web và các lựa chọn tương ứng để lấy dữ liệu về hệ gen người trên ngân hàng gen UCSC. Tương tự theo cách này, ta có thể lấy ra dữ liệu về hệ gen chuột, virus Ebola hay dữ liệu hệ gen của một số loại

vi khuẩn khác làm dữ liệu kiểm thử cho chương trình bằng cách thay thế lựa chọn ở mục clade và genome.

Hình 3.1. Giao diện mô phỏng cách lấy dữ liệu hệ gen người từ UCSC Table Browser

3.2. Mã hóa chƣơng trình tìm giao các đoạn gen

3.2.1. Ngôn ngữ và môi trƣờng lập trình

Để mô phỏng ứng dụng của cấu trúc dữ liệu cây quản lí đoạn trong bài toán tìm giao của các đoạn gen, tôi xây dựng chương trình ứng dụng “Tìm

giao các đoạn gen” sử dụng ngôn ngữ lập trình Java, môi trường NetBeans

IDE 8.0.1.

Java là một ngôn ngữ lập trình hướng đối tượng, dựa trên các lớp. Khác với phần lớn ngôn ngữ lập trình thông thường, thay vì biên dịch mã

nguồn thành mã máy hoặc thông dịch mã nguồn khi chạy, Java được thiết kế để biên dịch mã nguồn thành bytecode, bytecode sau đó sẽ được môi trường thực thi chạy. Trước đây, Java chạy chậm hơn những ngôn ngữ dịch thẳng ra mã máy như C và C++, nhưng sau này nhờ công nghệ "biên dịch tại chỗ", khoảng cách này đã được thu hẹp, và trong một số trường hợp đặc biệt Java có thể chạy nhanh hơn. So với C#, một ngôn ngữ khá tương đồng về mặt cú pháp và quá trình dịch/chạy, Java chạy nhanh tương đương.

Cú pháp Java được vay mượn nhiều từ C, C++ nhưng có cú pháp hướng đối tượng đơn giản hơn và ít tính năng xử lý cấp thấp hơn. Do đó việc viết một chương trình bằng Java dễ hơn, đơn giản hơn, đỡ tốn công sửa lỗi hơn.

Trong Java, hiện tượng rò rỉ bộ nhớ hầu như không xảy ra do bộ nhớ được quản lí bởi Java Virtual Machine bằng cách tự động "dọn dẹp rác". Người lập trình không phải quan tâm đến việc cấp phát và xóa bộ nhớ như C, C++. Điều này hoàn toàn có lợi khi ta triển khai một ứng dụng cần cấp phát nhiều bộ nhớ, khối lượng dữ liệu lớn, có quy mô như một hệ gen.

Bên cạnh đó, NetBeans là một công cụ hoàn toàn miễn phí, hỗ trợ nhiều hệ điều hành khác nhau như Windows, Mac, Linux, và Solaris. NetBeans bao gồm một môi trường phát triển tích hợp IDE mã nguồn mở và một nền tảng ứng dụng cho phép thiết kế và lập trình các chương trình Java một cách dễ dàng, nhanh chóng và nhẹ nhàng.

Tất cả những ưu điểm kể ra trên đây của cả Java và NetBeans rất phù hợp để triển khai chương trình “Tìm giao các đoạn gen”.

Chương trình “Tìm giao các đoạn gen” được thiết kế gồm hai chức năng chính, tương đương với hai trường hợp của bài toán đã phát biểu đó là cửa sổ truy vấn gen thực hiện tìm giao của một đoạn gen với các đoạn gen trong một

Một phần của tài liệu (LUẬN văn THẠC sĩ) cây quản lí đoạn và ứng dụng (Trang 36)

Tải bản đầy đủ (PDF)

(65 trang)