Нижче я написав відповідь n
рівним 5, але ви можете застосувати той самий підхід, щоб намалювати DFA для будь-якого значення n
та "будь-якої позиційної системи числення", наприклад, двійковий, трійковий ...
Спочатку схильний термін "Повна DFA", DFA, визначена на повному домені в δ: Q × Σ → Q, називається "Повна DFA". Іншими словами, ми можемо сказати; у діаграмі переходу повної DFA відсутній край (наприклад, з кожного стану в Q присутній по одному вихідному краю для кожного символу мови в Σ). Примітка: Часом ми визначаємо частковий DFA як δ ⊆ Q × Σ → Q (Читати: Як читається “δ: Q × Σ → Q” у визначенні DFA ).
Дизайн DFA приймає двійкові числа, що діляться на число 'n':
Крок 1 : Коли ви ділите число ω на n
той час, нагадування може бути 0, 1, ..., (n - 2) або (n - 1). Якщо залишок - 0
це означає, що ω ділиться, n
інакше ні. Отже, у моєму DFA буде стан q r, який відповідав би значенню залишку r
, де 0 <= r <= (n - 1)
, і загальна кількість станів у DFA n
.
Після обробки числового рядка ω над Σ кінцевий стан q r означає, що ω% n => r (% оператора нагадування).
У будь-яких автоматах призначення стану схоже на елемент пам'яті. Стан в атоматах зберігає деяку інформацію, таку як перемикач вентилятора, яка може визначити, чи є вентилятор у вимкненому чи ввімкненому стані. Для n = 5, п’ять станів у DFA, що відповідають п’яти відомостям нагадування, наступним чином:
- Стан q 0 досягнуто, якщо нагадування дорівнює 0. Стан q 0 є кінцевим станом (стан прийняття). Це також початковий стан.
- Стан q 1 досягає, якщо нагадування дорівнює 1, не остаточний стан.
- Укажіть q 2, якщо нагадування дорівнює 2, не остаточний стан.
- Укажіть q 3, якщо нагадування 3, не остаточний стан.
- Укажіть q 4, якщо нагадування дорівнює 4, не остаточний стан.
Використовуючи вищезазначену інформацію, ми можемо розпочати малювання діаграми переходів TD з п’яти станів таким чином:
Фігура 1
Отже, 5 станів для 5 значень залишку. Після обробки рядка ω, якщо кінцевий стан стає q 0, це означає, що десятковий еквівалент вхідного рядка ділиться на 5. На наведеному вище рисунку q 0 позначений кінцевим станом як два концентричних кола.
Крім того, я визначив правило переходу δ: (q 0 , 0) → q 0 як самоцикл для символу '0'
в стані q 0 , це тому, що десятковий еквівалент будь-якого рядка, що складається лише з '0'
0, і 0 ділиться на n
.
Крок-2 : TD вище неповний; і може обробляти лише рядки '0'
s. Тепер додайте ще кілька ребер, щоб він міг обробляти наступні числові рядки. Перевірте таблицю нижче, показує нові правила переходу, які можна додати наступним кроком:
┌──────┬───────────────────┬─────────┐
│ Номер │ Двійковий │ Залишок (% 5) │ Кінцевий стан │
├──────┼───────────────────┼─────────┤
│Один │1 │1 │q 1 │
├──────┼───────────────────┼─────────┤
│дві │10 │2 │q 2 │
├──────┼───────────────────┼─────────┤
│Три │11 │3 │q 3 │
├──────┼───────────────────┼─────────┤
│Четверо │100 │4 │q 4 │
└──────┴───────────────────┴─────────┘
- Для обробки двійкового рядка
'1'
повинно бути правило переходу δ: (q 0 , 1) → q 1
- Два: - двійкове представлення є
'10'
, кінцевий стан повинен бути q 2 , і для обробки '10'
нам просто потрібно додати ще одне правило переходу δ: (q 1 , 0) → q 2
Шлях : → (q 0 ) ─1 → ( q 1 ) ─0 → (q 2 )
- Три: - у двійковому вигляді це
'11'
, кінцевий стан дорівнює q 3 , і нам потрібно додати правило переходу δ: (q 1 , 1) → q 3
Шлях : → (q 0 ) ─1 → (q 1 ) ─1 → (q 3 )
- Четверте: - у двійковому режимі
'100'
кінцевий стан дорівнює q 4 . TD вже обробляє префіксний рядок, '10'
і нам просто потрібно додати нове правило переходу δ: (q 2 , 0) → q 4
Шлях : → (q 0 ) ─1 → (q 1 ) ─0 → (q 2 ) ─0 → (q 4 )
Малюнок-2
Крок-3 : П'ять = 101
Наведена вище схема переходів на малюнку-2 все ще неповна і є багато відсутніх країв, наприклад, для δ не визначено переходу: (q 2 , 1) - ? . І правило має бути присутнім для обробки рядків типу '101'
.
Оскільки '101'
= 5 ділиться на 5, і для прийняття '101'
я додаю δ: (q 2 , 1) → q 0 на малюнку-2.
Шлях: → (q 0 ) ─1 → (q 1 ) ─0 → (q 2 ) ─1 → (q 0 )
з цим новим правилом, діаграма переходів стає такою:
Малюнок-3
Нижче на кожному кроці я вибираю наступне наступне двійкове число, щоб додати відсутні ребра, поки не отримаю TD як "повний DFA".
Крок-4 : Шість = 110.
Ми можемо обробити '11'
в поточному TD на малюнку-3 як: → (q 0 ) ─11 → (q 3 ) ─0 → ( ? ). Оскільки 6% 5 = 1, це означає додати одне правило δ: (q 3 , 0) → q 1 .
Малюнок-4
Крок 5 : Сім = 111
┌──────┬───────────────────┬───────────────────── ─┬───────────┐
│ Номер │ Двійковий │ Залишок (% 5) │ Кінцевий стан │ Шлях │ Додати │
├──────┼───────────────────┼───────────────────── ─┼───────────┤
│Сім │111 │7% 5 = 2 │q 2 │ q 0 ─11 → q 3 │ q 3 ─1 → q 2 │
└──────┴───────────────────┴───────────────────── ─┴───────────┘
Малюнок-5
Крок 6 : Вісім = 1000
┌┌ ─────────┐
│ Номер │ Двійковий │ Залишок (% 5) │ Кінцевий стан │ Шлях │ Додати │
├──────┼───────────────────┼───────────────────┼ ─────────┤
│ Вісім │1000 │8% 5 = 3 │q 3 │q 0 ─100 → q 4 │ q 4 ─0 → q 3 │
└──────┴───────────────────┴───────────────────┴ ─────────┘
Малюнок-6
Крок 7 : Дев'ять = 1001
┌┌ ─────────┐
│ Номер │ Двійковий │ Залишок (% 5) │ Кінцевий стан │ Шлях │ Додати │
├──────┼───────────────────┼───────────────────┼ ─────────┤
│Дев’ять │1001 │9% 5 = 4 │q 4 │q 0 ─100 → q 4 │ q 4 ─1 → q 4 │
└──────┴───────────────────┴───────────────────┴ ─────────┘
Малюнок-7
У TD-7 загальна кількість ребер дорівнює 10 == Q × Σ = 5 × 2. І це повний DFA, який може приймати всі можливі двійкові рядки, десяткові еквіваленти діляться на 5.
Дизайн DFA приймає потрійні числа, що діляться на номер n:
Крок-1 Точно так само, як і для двійкових файлів, використовуйте малюнок-1.
Крок-2 Додайте нуль, один, два
┌───────┬───────┬────────────┬─────────┬───────── ─────┐
│ Десятковий │ Трійковий │ Залишок (% 5) │ Кінцевий стан │ Додати │
├───────┼───────┼────────────┼─────────┼───────── ─────┤
│Знуля │0 │0 │q0 │ δ: (q0,0) → q0 │
├───────┼───────┼────────────┼─────────┼───────── ─────┤
│Одне │1 │1 │q1 │ δ: (q0,1) → q1 │
├───────┼───────┼────────────┼─────────┼───────── ─────┤
│Дві │2 │2 │q2 │ δ: (q0,2) → q3 │
└───────┴───────┴────────────┴─────────┴───────── ─────┘
Малюнок-8
Крок-3 Додайте три, чотири, п’ять
┌───────┬───────┬────────────┬─────────┬───────── ────┐
│ Десятковий │ Трійковий │ Залишок (% 5) │ Кінцевий стан │ Додати │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Три │10 │3 │q3 │ δ: (q1,0) → q3 │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Четверо │11 │4 │q4 │ δ: (q1,1) → q4 │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│п’ять │12 │0 │q0 │ δ: (q1,2) → q0 │
└───────┴───────┴────────────┴─────────┴───────── ────┘
Малюнок-9
Крок-4 Додайте шість, сім, вісім
┌───────┬───────┬────────────┬─────────┬───────── ────┐
│ Десятковий │ Трійковий │ Залишок (% 5) │ Кінцевий стан │ Додати │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Шість │20 │1 │q1 │ δ: (q2,0) → q1 │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Сім │21 │2 │q2 │ δ: (q2,1) → q2 │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│ Вісім │22 │3 │q3 │ δ: (q2,2) → q3 │
└───────┴───────┴────────────┴─────────┴───────── ────┘
Малюнок-10
Крок-5 Додайте дев’ять, десять, одинадцять
┌───────┬───────┬────────────┬─────────┬───────── ────┐
│ Десятковий │ Трійковий │ Залишок (% 5) │ Кінцевий стан │ Додати │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Дев’ять │100 │4 │q4 │ δ: (q3,0) → q4 │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Десять101 │0 │q0 │ δ: (q3,1) → q0 │
├───────┼───────┼────────────┼─────────┼───────── ────┤
│Одинадцять │102 │1 │q1 │ δ: (q3,2) → q1 │
└───────┴───────┴────────────┴─────────┴───────── ────┘
Малюнок-11
Крок-6 Додайте дванадцять, тринадцять, чотирнадцять
┌────────┬───────┬────────────┬─────────┬──────── ─────┐
│ Десятковий │ Трійковий │ Залишок (% 5) │ Кінцевий стан │ Додати │
├────────┼───────┼────────────┼─────────┼──────── ─────┤
│Дванадцять │110 │2 │q2 │ δ: (q4,0) → q2 │
├────────┼───────┼────────────┼─────────┼──────── ─────┤
│Тринадцять│111 │3 │q3 │ δ: (q4,1) → q3 │
├────────┼───────┼────────────┼─────────┼──────── ─────┤
│Чотирнадцять│112 │4 │q4 │ δ: (q4,2) → q4 │
└────────┴───────┴────────────┴─────────┴──────── ─────┘
Малюнок-12
Загальна кількість ребер на діаграмі переходу на малюнку 12 дорівнює 15 = Q × Σ = 5 * 3 (повний DFA). І цей DFA може приймати всі рядки, що складаються з {0, 1, 2}, ці десяткові еквіваленти діляться на 5.
Якщо ви помічаєте на кожному кроці, у таблиці є три записи, оскільки на кожному кроці я додаю всі можливі вихідні ребра із стану зробити повний DFA (і я додаю фронт, щоб q r стан отримав для залишку r
)!
Щоб додати далі, пам’ятайте, об’єднання двох регулярних мов також є регулярним. Якщо вам потрібно розробити DFA, який приймає двійкові рядки, ці десяткові еквіваленти діляться на 3 або 5, тоді намалюйте два окремі DFA для ділення на 3 і 5, а потім об'єднайте обидва DFA для побудови цільового DFA (для 1 <= n <= 10 ви повинні об'єднати 10 DFA).
Якщо вас попросять намалювати DFA, який приймає двійкові рядки так, щоб десятковий еквівалент ділився на 5 і 3, тоді ви шукаєте DFA, що ділиться на 15 (але як щодо 6 і 8?).
Примітка: DFA, намальовані за допомогою цієї техніки, будуть мінімізовані DFA лише тоді, коли між числом і базою немає спільного множника, n
наприклад, у першому прикладі немає між 5 і 2 або у другому прикладі між 5 і 3, отже, обидва побудовані вище DFA мінімізовані DFA. Якщо ви зацікавлені читати далі про можливі міні-стани для числа n
та базової b
статті для читання: Подільність та складність стану .
нижче я додав скрипт Python, я написав його для розваги під час вивчення бібліотеки Python pygraphviz. Я додаю, сподіваюся, це може якось комусь допомогти.
Розробити DFA для базових рядків числа "b", що діляться на число "n":
Отже, ми можемо застосувати вищеописаний фокус, щоб намалювати DFA для розпізнавання числових рядків у будь-якій основі, 'b'
які діляться на дане число 'n'
. У цьому DFA загальна кількість станів буде n
(для n
залишків), а кількість ребер має дорівнювати 'b' * 'n' - це повний DFA: 'b' = кількість символів на мові DFA і 'n' = кількість штатів.
Використовуючи вищеописаний трюк, нижче я написав сценарій Python, щоб намалювати DFA для введення base
та number
. У сценарії функція divided_by_N
заповнює правила переходу DFA base * number
кроками. У кожному кроці-num я перетворюю num
в числовий рядок num_s
за допомогою функції baseN()
. Щоб уникнути обробки кожного числового рядка, я використав тимчасову структуру даних lookup_table
. На кожному кроці кінцевий стан для числового рядка num_s
обчислюється та зберігається lookup_table
для використання на наступному кроці.
Для графіку переходів DFA я написав функцію draw_transition_graph
за допомогою бібліотеки Pygraphviz (дуже проста у використанні). Для використання цього сценарію вам потрібно встановити graphviz
. Щоб додати кольорові краї на діаграмі переходів, я випадково генерую кольорові коди для кожної get_color_dict
функції символу .
import pygraphviz as pgv
from pprint import pprint
from random import choice as rchoice
def baseN(n, b, syms="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
""" converts a number `n` into base `b` string """
return ((n == 0) and syms[0]) or (
baseN(n//b, b, syms).lstrip(syms[0]) + syms[n % b])
def divided_by_N(number, base):
"""
constructs DFA that accepts given `base` number strings
those are divisible by a given `number`
"""
ACCEPTING_STATE = START_STATE = '0'
SYMBOL_0 = '0'
dfa = {
str(from_state): {
str(symbol): 'to_state' for symbol in range(base)
}
for from_state in range(number)
}
dfa[START_STATE][SYMBOL_0] = ACCEPTING_STATE
lookup_table = { SYMBOL_0: ACCEPTING_STATE }.setdefault
for num in range(number * base):
end_state = str(num % number)
num_s = baseN(num, base)
before_end_state = lookup_table(num_s[:-1], START_STATE)
dfa[before_end_state][num_s[-1]] = end_state
lookup_table(num_s, end_state)
return dfa
def symcolrhexcodes(symbols):
"""
returns dict of color codes mapped with alphabets symbol in symbols
"""
return {
symbol: '#'+''.join([
rchoice("8A6C2B590D1F4E37") for _ in "FFFFFF"
])
for symbol in symbols
}
def draw_transition_graph(dfa, filename="filename"):
ACCEPTING_STATE = START_STATE = '0'
colors = symcolrhexcodes(dfa[START_STATE].keys())
tg = pgv.AGraph(strict=False, directed=True, decorate=True)
for from_state in dfa:
for symbol, to_state in dfa[from_state].iteritems():
tg.add_edge("Q%s"%from_state, "Q%s"%to_state,
label=symbol, color=colors[symbol],
fontcolor=colors[symbol])
tg.add_node('null', shape='plaintext', label='start')
tg.add_edge('null', "Q%s"%START_STATE,)
tg.get_node("Q%s"%ACCEPTING_STATE).attr['shape'] = 'doublecircle'
tg.draw(filename, prog='circo')
tg.close()
def print_transition_table(dfa):
print("DFA accepting number string in base '%(base)s' "
"those are divisible by '%(number)s':" % {
'base': len(dfa['0']),
'number': len(dfa),})
pprint(dfa)
if __name__ == "__main__":
number = input ("Enter NUMBER: ")
base = input ("Enter BASE of number system: ")
dfa = divided_by_N(number, base)
print_transition_table(dfa)
draw_transition_graph(dfa)
Виконайте його:
~/study/divide-5/script$ python script.py
Enter NUMBER: 5
Enter BASE of number system: 4
DFA accepting number string in base '4' those are divisible by '5':
{'0': {'0': '0', '1': '1', '2': '2', '3': '3'},
'1': {'0': '4', '1': '0', '2': '1', '3': '2'},
'2': {'0': '3', '1': '4', '2': '0', '3': '1'},
'3': {'0': '2', '1': '3', '2': '4', '3': '0'},
'4': {'0': '1', '1': '2', '2': '3', '3': '4'}}
~/study/divide-5/script$ ls
script.py filename.png
~/study/divide-5/script$ display filename
Вихід:
DFA приймає числові рядки в основі 4, які діляться на 5
Подібним чином введіть base = 4 і number = 7 для створення - dfa приймає числовий рядок в основі '4', які діляться на '7'
Btw, спробуйте змінити filename
на .png
або .jpeg
.
Посилається на тих, кого я використовую для написання цього сценарію:
➊ Функція baseN
з "перетворити ціле число на рядок у заданій числовій основі в python"
➋ Встановити "pygraphviz": "Python не бачить pygraphviz"
➌ Навчитися користуватися Pygraphviz: "Python- FSM "
➍ Сформувати випадкові шістнадцяткові кольорові коди для кожного мовного символу: " Як мені створити генератор випадкових шістнадцяткових кодів, використовуючи .join та для циклів? "
n
це тривіально, так?