forked from jiangyiminmike/COMP9021_19T1
-
Notifications
You must be signed in to change notification settings - Fork 0
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
0 parents
commit a9e406c
Showing
3 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
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,136 @@ | ||
# Written by *** and Eric Martin for COMP9021 | ||
import re | ||
|
||
''' | ||
See https://en.wikipedia.org/wiki/Deterministic_finite_automaton | ||
We consider as alphabet a set of digits. | ||
We accept partial transition functions (that is, there might be no transition | ||
for a given state and symbol). | ||
With the accepts() function, we will deal with a single accept state rather than | ||
a set of accept states. | ||
In the test cases below, transitions_2 is the wikipedia example | ||
(with 'S1' and 'S2' renamed as 'state_1' and 'state_2', respectively), | ||
so the automaton that with 'state_1' as both initial and unique accept state, | ||
accepts words with an even number of occurrences of 0's. | ||
''' | ||
|
||
|
||
def describe_automaton(transitions): | ||
''' | ||
The output is produced with the print() function. | ||
>>> transitions_1 = {('q0', 0): 'q1', ('q1', 1): 'q0'} | ||
>>> describe_automaton(transitions_1) | ||
When in state "q0" and processing "0", automaton's state becomes "q1". | ||
When in state "q1" and processing "1", automaton's state becomes "q0". | ||
>>> transitions_2 = {('state_1', 0): 'state_2', ('state_1', 1): 'state_1',\ | ||
('state_2', 0): 'state_1', ('state_2', 1): 'state_2'} | ||
>>> describe_automaton(transitions_2) | ||
When in state "state_1" and processing "0", automaton's state becomes "state_2". | ||
When in state "state_1" and processing "1", automaton's state becomes "state_1". | ||
When in state "state_2" and processing "0", automaton's state becomes "state_1". | ||
When in state "state_2" and processing "1", automaton's state becomes "state_2". | ||
''' | ||
# 直接遍历 | ||
keys = transitions.keys() | ||
for index in range(0, len(transitions)): | ||
(state, code) = keys[index] | ||
value = transitions.get((state, code)) | ||
print(f'When in state "{state}" and processing "{code}", \ | ||
automaton\'s state becomes "{value}".') | ||
|
||
# 利用dict的key | ||
for (state, code) in transitions.keys(): | ||
print(f'When in state "{state}" and processing "{code}", \ | ||
automaton\'s state becomes "{transitions[(state, code)]}".') | ||
|
||
# 高级用法 | ||
for (state, code) in transitions: | ||
print(f'When in state "{state}" and processing "{code}", \ | ||
automaton\'s state becomes "{transitions[(state, code)]}".') | ||
|
||
# 另外一种高级用法 | ||
for (state, code), value in transitions.items(): | ||
print(f'When in state "{state}" and processing "{code}", \ | ||
automaton\'s state becomes "{value}".') | ||
|
||
|
||
def transitions_as_dict(transitions_as_list): | ||
''' | ||
transitions_as_list is a list of strings of the form 'state_1,symbol:state_2' | ||
where 'state_1' and 'state_2' are words and 'symbol' is one of the 10 digits. | ||
We assume that there is at most one 'state_2' for given 'state_1' and 'symbol'. | ||
>>> transitions_as_dict(['q0,0:q1', 'q1,1:q0']) | ||
{('q0', 0): 'q1', ('q1', 1): 'q0'} | ||
>>> transitions_as_dict(['state_1,0:state_2', 'state_1,1:state_1',\ | ||
'state_2,0:state_1', 'state_2,1:state_2']) | ||
{('state_1', 0): 'state_2', ('state_1', 1): 'state_1', \ | ||
('state_2', 0): 'state_1', ('state_2', 1): 'state_2'} | ||
''' | ||
|
||
# define variables | ||
transitions = {} | ||
# for each line | ||
for line in transitions_as_list: | ||
# split or re | ||
state, code, new_state = re.split('[,:]', line) | ||
# check all the value is correct | ||
if state and code and new_state: | ||
# set result | ||
transitions[state, int(code)] = new_state | ||
|
||
return transitions | ||
|
||
|
||
def accepts(transitions, word, initial_state, accept_state): | ||
''' | ||
Starting in 'initial_state', if the automaton can process with 'transitions' | ||
all symbols in 'word' and eventually reach 'accept_state', then the function | ||
returns True; otherwise it returns False. | ||
>>> transitions_1 = {('q0', 0): 'q1', ('q1', 1): 'q0'} | ||
>>> accepts(transitions_1, '00', 'q0', 'q1') | ||
False | ||
>>> accepts(transitions_1, '2', 'q0', 'q0') | ||
False | ||
>>> accepts(transitions_1, '0101010', 'q0', 'q0') | ||
False | ||
>>> accepts(transitions_1, '01010101', 'q0', 'q0') | ||
True | ||
>>> not accepts(transitions_1, '01', 'q0', 'q1') and\ | ||
accepts(transitions_1, '010', 'q0', 'q1') | ||
True | ||
>>> transitions_2 = {('state_1', 0): 'state_2', ('state_1', 1): 'state_1',\ | ||
('state_2', 0): 'state_1', ('state_2', 1): 'state_2'} | ||
>>> accepts(transitions_2, '011', 'state_1', 'state_1') | ||
False | ||
>>> accepts(transitions_2, '001110000', 'state_1', 'state_1') | ||
True | ||
>>> accepts(transitions_2, '1011100101', 'state_1', 'state_1') | ||
True | ||
>>> accepts(transitions_2, '10111000101', 'state_1', 'state_1') | ||
False | ||
''' | ||
for char in word: | ||
if (initial_state, int(char)) not in transitions: | ||
return False | ||
initial_state = transitions[initial_state, int(char)] | ||
|
||
return initial_state == accept_state | ||
|
||
|
||
if __name__ == '__main__': | ||
# import doctest | ||
|
||
# doctest.testmod() | ||
|
||
transitions_1 = {('q0', 0): 'q1', ('q1', 1): 'q0'} | ||
describe_automaton(transitions_1) |
Binary file not shown.
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,142 @@ | ||
# Written by *** and Eric Martin for COMP9021 | ||
|
||
|
||
def rule_encoded_by(rule_nb): | ||
''' | ||
"rule_nb" is supposed to be an integer between 0 and 15. | ||
''' | ||
values = [int(d) for d in f'{rule_nb:04b}'] | ||
return {(p // 2, p % 2): values[p] for p in range(4)} | ||
|
||
|
||
def describe_rule(rule_nb): | ||
''' | ||
"rule_nb" is supposed to be an integer between 0 and 15. | ||
>>> describe_rule(3) | ||
The rule encoded by 3 is: {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1} | ||
After 0 followed by 0, we draw 0 | ||
After 0 followed by 1, we draw 0 | ||
After 1 followed by 0, we draw 1 | ||
After 1 followed by 1, we draw 1 | ||
>>> describe_rule(4) | ||
The rule encoded by 4 is: {(0, 0): 0, (0, 1): 1, (1, 0): 0, (1, 1): 0} | ||
After 0 followed by 0, we draw 0 | ||
After 0 followed by 1, we draw 1 | ||
After 1 followed by 0, we draw 0 | ||
After 1 followed by 1, we draw 0 | ||
>>> describe_rule(11) | ||
The rule encoded by 11 is: {(0, 0): 1, (0, 1): 0, (1, 0): 1, (1, 1): 1} | ||
After 0 followed by 0, we draw 1 | ||
After 0 followed by 1, we draw 0 | ||
After 1 followed by 0, we draw 1 | ||
After 1 followed by 1, we draw 1 | ||
>>> describe_rule(14) | ||
The rule encoded by 14 is: {(0, 0): 1, (0, 1): 1, (1, 0): 1, (1, 1): 0} | ||
After 0 followed by 0, we draw 1 | ||
After 0 followed by 1, we draw 1 | ||
After 1 followed by 0, we draw 1 | ||
After 1 followed by 1, we draw 0 | ||
''' | ||
rule = rule_encoded_by(rule_nb) | ||
print('The rule encoded by', rule_nb, 'is: ', rule) | ||
# print() | ||
# INSERT YOUR CODE HERE TO PRINT 4 LINES | ||
for (first, second), last in rule.items(): | ||
print(f"After {first} followed by {second}, we draw {last}") | ||
|
||
|
||
def draw_line(rule_nb, first, second, length): | ||
''' | ||
"rule_nb" is supposed to be an integer between 0 and 15. | ||
"first" and "second" are supposed to be the integer 0 or the integer 1. | ||
"length" is supposed to be a positive integer (possibly equal to 0). | ||
Draws a line of length "length" consisting of 0's and 1's, | ||
that starts with "first" if "length" is at least equal to 1, | ||
followed by "second" if "length" is at least equal to 2, | ||
and with the remaining "length" - 2 0's and 1's determined by "rule_nb". | ||
>>> draw_line(3, 0, 0, 1) | ||
0 | ||
>>> draw_line(3, 1, 0, 5) | ||
10101 | ||
>>> draw_line(4, 1, 0, 9) | ||
100000000 | ||
>>> draw_line(4, 0, 1, 13) | ||
0110000000000 | ||
>>> draw_line(11, 1, 0, 16) | ||
1010101010101010 | ||
>>> draw_line(11, 1, 1, 19) | ||
1111111111111111111 | ||
>>> draw_line(14, 0, 0, 21) | ||
001101101101101101101 | ||
>>> draw_line(14, 1, 0, 22) | ||
1011011011011011011011 | ||
''' | ||
rule = rule_encoded_by(rule_nb) | ||
# INSERT YOUR CODE HERE TO PRINT ONE LINE | ||
result = [] | ||
if length >= 1: | ||
result.append(first) | ||
if length >= 2: | ||
result.append(second) | ||
for i in range(2, length): | ||
temp = rule[(first, second)] | ||
result.append(temp) | ||
first = second | ||
second = temp | ||
|
||
print("".join((str(item) for item in result))) | ||
|
||
|
||
def uniquely_produced_by_rule(line): | ||
''' | ||
"line" is assumed to be a string consisting of nothing but 0's and 1's. | ||
Returns an integer n between 0 and 15 if the rule encoded by n is the | ||
UNIQUE rule that can produce "line"; otherwise, returns -1. | ||
>>> uniquely_produced_by_rule('1100110011') | ||
12 | ||
>>> uniquely_produced_by_rule('01100000') | ||
4 | ||
>>> uniquely_produced_by_rule('001101101') | ||
14 | ||
>>> uniquely_produced_by_rule('11111111') | ||
-1 | ||
>>> uniquely_produced_by_rule('00011') | ||
-1 | ||
>>> uniquely_produced_by_rule('11001') | ||
-1 | ||
>>> uniquely_produced_by_rule('0010001') | ||
-1 | ||
>>> uniquely_produced_by_rule('0010001') | ||
-1 | ||
>>> uniquely_produced_by_rule('11111111111111110') | ||
-1 | ||
''' | ||
# REPLACE pass ABOVE WITH YOUR CODE | ||
rules = {} | ||
if len(line) >= 2: | ||
first, second = line[0], line[1] | ||
|
||
for last in line[2:]: | ||
if (first, second) in rules and rules[(first, second)] != last: | ||
return -1 | ||
else: | ||
rules[(first, second)] = last | ||
first, second = second, last | ||
|
||
if len(rules) == 4: | ||
keys = [('0', '0'), ('0', '1'), ('1', '0'), ('1', '1')] | ||
result = "" | ||
for key in keys: | ||
result += rules[key] | ||
return int(result, 2) | ||
else: | ||
return -1 | ||
|
||
|
||
if __name__ == '__main__': | ||
import doctest | ||
doctest.testmod() | ||
# print(uniquely_produced_by_rule('1100110011')) |