Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
KL-LAB8(9).doc
Скачиваний:
18
Добавлен:
12.02.2016
Размер:
2 Мб
Скачать
☆

3.2 Динамічне програмування

Динамічне програмування основний метод розробки алгоритмів, який знайшов широке використання в обробці природної мови. Термін'програмування' використовується в значенні планування або складання розкладу. Динамічне програмування використовується коли задача містить підзадачі, що перетинаються. Замість повторного рішення цих під задач ці рішення зберігаються в таблиці.

Пінгала – давній індійський поет і математик близько 5-го століття до н.е. написав трактат на санскриті про просодії Чандас-шастра (Chandas Shastra). Віраханка розширив цю роботу в6-му столітті н.е. вивчаючи способи комбінування коротких і довгих складів для одержання метрики розміруn. Коротким складамS, присвоювалась одна одиниця довжини а довгимL, дві одиниці довжини. Пінгала визначив, наприклад, що існують п’ять способів одержання метрики довжиною 4: V4 = {LL, SSL, SLS, LSS, SSSS}. V4 можна поділити на дві підмножини, що починаються зL і починаються зS, як показано в (1).

(1)

V4 =

LL, LSS

i.e. L prefixed to each item of V2 = {L, SS}

SSL, SLS, SSSS

i.e. S prefixed to each item of V3 = {SL, LS, SSS}

V3 =

LS

i.e. L prefixed to each item of V1 = {S}

SL, SSS

i.e. S prefixed to each item of V2 = {L, SS}}

V2 =

L

i.e. L prefixed to each item of V0 = {}

SS

i.e. S prefixed to each item of V1 = {S}

V1 = S

V0 = {}

 

def virahanka1(n):

if n == 0:

return [""]

elif n == 1:

return ["S"]

else:

s = ["S" + prosody for prosody in virahanka1(n-1)]

l = ["L" + prosody for prosody in virahanka1(n-2)]

return s + l

def virahanka2(n):

lookup = [[""], ["S"]]

for i in range(n-1):

s = ["S" + prosody for prosody in lookup[i+1]]

l = ["L" + prosody for prosody in lookup[i]]

lookup.append(s + l)

return lookup[n]

def virahanka3(n, lookup={0:[""], 1:["S"]}):

if n not in lookup:

s = ["S" + prosody for prosody in virahanka3(n-1)]

l = ["L" + prosody for prosody in virahanka3(n-2)]

lookup[n] = s + l

return lookup[n]

from nltk import memoize

@memoize

def virahanka4(n):

if n == 0:

return [""]

elif n == 1:

return ["S"]

else:

s = ["S" + prosody for prosody in virahanka4(n-1)]

l = ["L" + prosody for prosody in virahanka4(n-2)]

return s + l

 

>>> virahanka1(4)

['SSSS', 'SSL', 'SLS', 'LSS', 'LL']

>>> virahanka2(4)

['SSSS', 'SSL', 'SLS', 'LSS', 'LL']

>>> virahanka3(4)

['SSSS', 'SSL', 'SLS', 'LSS', 'LL']

>>> virahanka4(4)

['SSSS', 'SSL', 'SLS', 'LSS', 'LL']

Виходячи з (1) можна написати просту рекурсивну функціюvirahanka1() для обчислення цієї метрики. Для обчисленняV4 потрібно обчислити спочатку V3 та V2. Але для обчисленняV3, потрібно спочатку обчислити V2 та V1. Структуру обчислено показано в (2).

(2)

Для обчислення V4потрібно двічі обчислити V2 . Такі обчислення не повинні викликати труднощів, але при великих значеннях n виконувати ці обчислення стає не раціонально і складно. Для обчислення V20 використовуючи рекурсіюV2 потрібно обчислити4,181 раз; а для V40 потрібноV2 обчислити63,245,986 разів! Альтернативою може бути збереження значення V2 в таблиці та використання цього значення при потребі. Так само потрібно зробити і для обчислення V3 та інших. Функція virahanka2() реалізовує підхід динамічного програмування до вирішення цієї задачі. Робота функції полягає в заповненні таблиці (lookup) проміжними рішеннями задачі і її виконання припиняється при досягненні потібногоn . Кожна підзадача вирішується тільки один раз.

Підхід запропонований в virahanka2() полягає в рішенні малих задач для вирішення великої задачі. Відповідно, це підхід знизу – вверх до динамічного. На жаль, такий підхід має низьку ефективність при вирішення деяких задач, оскільки, від передбачає рішення під задач, які ніколи потім не використовуються для рішення основної задачі. Уникнути таких обчислень дозволяє підхід зверху-вниз до динамічного програмування, який ілюструє функціяvirahanka3.Ця функція уникає непотрібних обчислень, як вvirahanka1(), перевіряючи чи є вже збережений такий результат. Якщо ні функція рекурсивно його обчислює і зберігає у таблиці. Останній крок роботи це повернення збережених результатів. Остаточне рішення – функціяvirahanka4(), яка використовує“декоратор”Python memoize, який дозволяє зберігати допоміжні результати виконані virahanka3(). Процес "memoization" запам’ятовування полягає в збереженні результатів всіх попередніх викликів функції разом з параметрами, які використовувались. Якщо функція викликається з тими самими параметрами то повертається збережений результат , замість повторного обчислення функції.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]