تبدیل باروز-ویلر

تبدیل باروز-ویلر  یک الگوریتم است که چیدمان حروف در کلمات را تغییر می‌دهد. ان روش برای فشرده‌سازی داده‌ها بسیار مناسب است. اگر متنی که می‌خواهیم آن را فشرده کنیم شامل حروف تکراری ترجیحاً پشت سر هم باشد می‌توان از روش‌های دیگر فشرده سازی نظیر کدبندی طول اجرا (به انگلیسی: Run-length encoding) استفاده کرد. اما در حالات دیگر روش BWT بسیار مناسب می‌باشد مخصوصاً اینکه BWT الگوریتمی برگشت‌پذیر است. یعنی می‌توان متن فشرده سازی شده را به متن اولیه تبدیل کرد. در حقیقت این کار روشی است که فارغ از هر الگوریتم فشرده سازی که در آن استفاده می‌شود، با کمی محاسبات بیشتر میزان فشرده سازی را افزایش دهد.
BWT توسط مایکل باروز و دیوید ویلر در سال ۱۹۹۴ معرفی شد، زمانی که باروز در یک شرکت به نام DEC Systems Research Center مشغول به کار بود.

الگوریتم بدست آوردن BWT 
روش به دست آوردن BWT برای کلمهٔ EXAMPLE در شکل زیر نشان داده شده‌است. در ابتدا یک علامت مانند $ در انتهای آن قرار می‌دهیم تا بتوانیم کلمه را شیفت دورانی دهیم. خروجی‌های مربوط به شیفت در ستون سمت چپ آورده شده‌است. سپس در ستون سمت راست کلمات به دست آمده را به ترتیب حروف الفبا (به انگلیسی: Lexicographical order) مرتب می‌کنیم. ستون آخر که در شکل زیر به رنگ قرمز نمایش داده شده‌است، یعنی EXL$PAME همان (BWT(EXAMPLE می‌باشد.

شبه کد مربوط به این الگوریتم به شکل زیر می‌باشد:
 function BWT (string s)
    create a table, rows are all possible rotations of s
    sort rows alphabetically
    return (last column of the table)

الگوریتم BWT معکوس 
تا قبل از این روشی که گفته شد برای فشرده سازی استفاده می‌شود. حال اگر BWT یک کلمه را داشته باشیم چگونه باید بفهمیم اصل آنچه بوده‌است؟ برای این کار ابتدا حروف را شماره گذاره می‌کنیم. چون ممکن است در متن حروف تکراری داشته باشیم. مثلاً در مثال خودمان خواهیم داشت: E1-X1-A1-M1-P1-L1-E2 و ۱$.
برای بدست آوردن ماتریس مرتب شدهٔ اولیه ستوان آخر را که از نتیجهٔ فشرده سازی داریم. ستوان اول هم با مرتب کردن ستوان آخر بر اساس حروف الفبا به دست می‌آید. در ادامه به سطر اول نگاه می‌کنیم که ۱$ است. باید بفهمیم در کلمه اصلی بعد از این حرف چه حرفی قرار می‌گرفته‌است. با توجه به اینکه ما ماتریس را از طریق شیفت دورانی ساخته‌ایم پس اگر حرف ۱$ را در ستون آخر پیدا کرده و ببینیم در مقابل آن در سطر اول چه حرفی قرار دارد آن حرف، حرف بعدی ما در کلمه نهایی خواهد بود. همین کار را مدام انجام می‌دهیم تا کلمهٔ کامل به دست آید.
برای درک بهتر به مثال زیر توجه کنید:
همان‌طور که در بالا توضیح داده شد حرف بعد از ۱$ که X1 است را به دست آوردیم. حال به طریق مشابه می‌بینیم که X1 در کجای ستون آخر آمده‌است و حرف نظیر آن در ستون اول چیست؛ بنابراین می‌بینیم که مقابل آن A1 قرار دارد.

سپس A1 را در ستون آخر پیدا می‌کنیم و حرف نظیر آن در ستون اول را به عنوان حرف بعدی انتخاب می‌کنیم:

همین‌طور پیش می‌رویم تا سطر اول کامل شود:

سپس اعداد را حذف می‌کنیم و سطر اول را شیفت دورانی می‌دهیم تا $ در انتهای کلمه قرار بگیرد. اینگونه ما به کلمهٔ اولیه رسیده‌ایم:$EXAMPLE

شبه کد مربوط به این الگوریتم به شکل زیر است:
function inverseBWT (string s)
    create empty table
        // first insert creates first column
        insert s as a column of table before first column of the table
        sort rows of the table alphabetically
    return (row that ends with the 'EOF' character)

بهینه‌سازی 
روش‌هایی برای پیاده‌ساز بهتر خود الگوریتم وجود دارد تا حافظهٔ کمتری را اشغال کند. یا مثلاً ما نیازی نداریم حرف EOF را به کلمه ورودی اضافه می‌کنیم بلکه می‌توانیم برای آن یک اشاره گر نگه داریم. توضیحات بیشتر این الگوریتم را می‌توان در مطالعه کرد.

نمونه پیاده‌سازی 
کد مربوط به ساخت BWT به زبان پایتون در زیر آورده شده‌است:(برای درک بیشتر ۰۰۲\ , ۰۰۳\ به اسکی (استاندارد) مراجعه کنید. این دو کاراکتر مشخص کننده انتها و ابتدای کلمه هستند)

def bwt(s):
    """Apply Burrows-Wheeler transform to input string."""
    assert "\002" not in s and "\003" not in s, "Input string cannot contain STX and ETX characters"
    s = "\002" + s + "\003"  # Add start and end of text marker
    table = sorted(s[i:] + s[:i] for i in range(len(s)))  # Table of rotations of string
    last_column = [row[-1:] for row in table]  # Last characters of each row
    return "".join(last_column)  # Convert list of characters into string

برنامهٔ مربوط به معکوس BWT هم به شکل زیر می‌باشد:
def ibwt(r):
    """Apply inverse Burrows-Wheeler transform."""
    table = [""] * len(r)  # Make empty table
    for i in range(len(r)):
        table = sorted(r[i] + table[i] for i in range(len(r)))  # Add a column of r
    s = [row for row in table if row.endswith("\003")][0]  # Find the correct row (ending in ETX)
    return s.rstrip("\003").strip("\002")  # Get rid of start and end markers

روش زیر یک روش بهینه برای پیاده‌سازی BWT می‌باشد:

def bwt(s):
    """Apply Burrows-Wheeler transform to input string. Not indicated by a unique byte but use index list"""
    # Table of rotations of string
    table = [s[i:] + s[:i] for i in range(len(s))]
    # Sorted table
    table_sorted = table[:]
    table_sorted.sort()
    # Get index list of ((every string in sorted table)'s next string in unsorted table)'s index in sorted table
    indexlist = []
    for t in table_sorted:
        index1 = table.index(t)
        index1 = index1+1 if index1 < len(s)-1 else 0
        index2 = table_sorted.index(table[index1])
        indexlist.append(index2)
    # Join last characters of each row into string
    r = ''.join([row[-1] for row in table_sorted])
    return r, indexlist

def ibwt(r,indexlist):
    """Inverse Burrows-Wheeler transform. Not indicated by a unique byte but use index list"""
    s = ''
    x = indexlist[0]
    for _ in r:
        s = s + r[x]
        x = indexlist[x]
    return s

چگونگی فشرده سازی 
برای درک اینکه این الگوریتم چگونه به کمتر کردن حجم کمک می‌کند، متنی را در نظر بگیرید که در آن یک لغت خاص زیاد تکرار شده باشد مثلاً کلمه بیا، بعد از اجرا این تبدیل تمامی موارد تکرار شدن این کلمه در کنار هم مرتب می‌شوند و قرار می‌گیرند مثلاً به صورت «اب» که در این صورت می‌دانیم «ی» مربوط به این زیر رشته در آخر جمله است. پس تعداد زیادی ی پشت سر هم در آخر رشته تکرار می‌شود که این امر، کار فشرده‌سازی را برای بعضی الگوریتم‌های فشرده‌سازی متدوال ساده‌تر می‌کند.

کاربردها 
همان‌طور که پیش از این نیز ذکر شد، الگوریتم BWT در فشرده سازی کاربرد زیادی دارد. اما می‌توان در کاربردهای دیگری هم از آن استفاده کرد که یکی از آن‌ها تطبیق الگو می‌باشد. BWT یک روش سریع برای پیدا کردن الگوها در متن می‌باشد. از کاربردهای دیگر آن می‌توان به خوشه بندی اشاره کرد که در حوزه بینایی رایانه‌ای و ترجمه ماشینی استفاده می‌شود.

BWT در بیوانفورماتیک 
ظهور تعیین توالی دی‌ان‌ای در اواخر سال ۲۰۰۰ میلادی، باعث شد که کاربرد دیگری از BWT نمایان شود. در تعیین توالی دی‌ان‌ای، دی‌ان‌ای به قطعات کوچک‌تری تقسیم می‌شود که به هر کدام یک خوانده (به انگلیسی:read) می‌گویند. در بسیاری از آزمایش‌ها نیاز است که این خوانده‌ها به ژنوم مرجعی تطبیق داده شوند. در راستای کاهش حافظهٔ مورد نیاز برای هم‌ترازسازی توالی، الگوریتم‌های متنوعی استفاده شده‌اند (مانند Bowtie, BWA, SOAP2) که از BWT استفاده می‌کنند.

منابع 

 

الگوریتم‌های فشرده‌سازی بی‌اتلاف
تبدیل
فشرده‌سازی داده‌ها