I'm creating a state machine simplifier in Ruby. While looping through the table that I create to simplify the state machine, it runs through correctly and produces the desired output, however, I get the following error: :
undefined method `[]' for 0..5:Range (NoMethodError)
from C:/Users/Sara/workspace/StateMachineSimplifier/statemachine_simplifier.rb:64:in each
from C:/Users/Sara/workspace/StateMachineSimplifier/statemachine_simplifier.rb:64:in x_out
from C:/Users/Sara/workspace/StateMachineSimplifier/statemachine_simplifier.rb:268:in main
from C:/Users/Sara/workspace/StateMachineSimplifier/statemachine_simplifier.rb:274:in <main>
I know that the error is caused by my while loop that calls the function. How can I call the function only enough times to end up with the finalized table?
=begin
File: statemachine_simplifier.rb
Author: Sara Tibbetts
Date: 04/24/2015
Description: This program takes in .txt file with a state table
and reduces it to its simplest form
=end
def dup_remove(table0)
#Simplifies states with same output and next states
for i in 0..((table0.size)-1)
check1 = table0[i][1]
check2 = table0[i][2]
for j in 0..((table0.size)-1)
if i != j then
#States are exactly the same
if (table0[i][1] == table0[j][1]) and (table0[i][2] == table0[j][2]) then
#Replaces all instances of state to be removed with equivalent state
to_rep = table0[i][0]
to_rem = table0[j][0]
t_index = []
#Removes the state from the array
table0[j] = "-1"
for i in 0..((table0.size)-1)
for j in 0..((table0[0].size)-1)
if table0[i][j] == to_rem then
table0[i][j] = to_rep
end
end
end
end
end
end
end
#Removes the placeholders from the table
for i in 0..((table0.size)-1)
if table0[i] == "-1" then
t_index.push(i)
end
end
if t_index != nil then
for i in 0..((t_index.size)-1)
table0.delete_at(t_index[i])
for j in i..((t_index.size)-1)
t_index[j] = t_index[j]-1
end
end
end
#puts table0.inspect
return table0
end
#loops through the given array, and minimizes the states
def x_out(arr1, s_table)
#puts arr1.inspect
#puts arr1.size
for i in 0..((arr1.size)-1)
#Loops through each row of the columns
#puts i
#puts arr1.inspect
#puts arr1[i].inspect
for j in 0..((arr1[i].size)-1)
#If the cell is not an "X"
if arr1[i][j].size != 1
#If the states are not equal
if arr1[i][j][0] != arr1[i][j][2] ###################1
#If the first state is less than the second state
if arr1[i][j][0] < arr1[i][j][2] ###################2
#If arr1[small-1][(big-2)-(small-1)] = "X"
if arr1[(arr1[i][j][0])-1][(arr1[i][j][2]-2)-(arr1[i][j][0]-1)] == "X" ###################3
arr1[i][j] = "X"
end ###################3
#If the first state is more than the second state
else ###################2
#If arr1[small-1][(big-2)-(small-1)] = "X"
if arr1[arr1[i][j][2]-1][(arr1[i][j][0]-2)-(arr1[i][j][2]-1)] == "X" ###################4
arr1[i][j] = "X"
end ###################4
end ###################2
end ###################1
if arr1[i][j].size != 1
#print "Loop 2", arr1.inspect, "\n"
#If the states are not equal
if arr1[i][j][1] != arr1[i][j][3]
#If the first state is less than the second state
if arr1[i][j][1] < arr1[i][j][3]
#puts arr1[i][j].inspect
#puts arr1[(arr1[i][j][1])-1][(arr1[i][j][3]-2)-(arr1[i][j][1]-1)].inspect
#If arr1[small-1][(big-2)-(small-1)] = "X"
if arr1[(arr1[i][j][1])-1][(arr1[i][j][3]-2)-(arr1[i][j][1]-1)] == "X"
arr1[i][j] = "X"
end
#If the first state is more than the second state
else
#If arr1[small-1][(big-2)-(small-1)] = "X"
if arr1[arr1[i][j][3]-1][(arr1[i][j][1]-2)-(arr1[i][j][3]-1)] == "X"
arr1[i][j] = "X"
end
end
end
end
end
end
end
end
def main()
#Reads in the .txt file
print("Enter a file: ")
filename = gets.chomp
#Creates array to store information from file
s_table = ""
i = 0
j = 0
f = File.open(filename,"r")
puts "\nState table input: \n"
f.each_line do |line|
puts line
s_table = s_table + line
end
s_table = s_table.split("\n")
s_table = s_table.map { |data| data.split(' ') }
#Groups states based on outputs
table1 = []
table0 = []
for i in 0..((s_table.size)-1)
if s_table[i][3] == "1" then
table1.push(s_table[i])
elsif s_table[i][3] == "0" then
table0.push(s_table[i])
end
end
while dup_remove(table0) != table0
table0 = dup_remove(table0)
end
while dup_remove(table1) != table1
table1 = dup_remove(table1)
end
#Removes the rest of the unnecessary states
#table of states that have the possibility of being combined
pos_comb = []
#Need to make table reflecting staircase [ [AB, AC, AD, AE, AF, AG], [BC, BD, BE, BF, BG], [CD, CE, CF, CG], [DE, DF, DG], [EF, EG], [FG] ]
for i in 0..((s_table.size)-2)
# 0 :6, 1: 5, 2:4 . . .
#(s_table.size)-(i+1)
pos_comb[i] = Array.new(s_table.size-(i+1), "0")
end
#puts pos_comb.inspect
#Creates an array with a numerical equivalent of the state number
s0_arr = Array.new(table0.size)
for i in 0..((s0_arr.size)-1)
if (table0[i][0].ord >= 30) && (table0[i][0].ord <= 57)
s0_arr[i] = table0[i][0]
elsif (table0[i][0].ord >= 65) && (table0[i][0].ord <= 90)
s0_arr[i] = table0[i][0].ord - 64
else
s0_arr[i] = table0[i][0].ord - 96
end
end
s1_arr = Array.new(table1.size)
for i in 0..((s1_arr.size)-1)
if (table1[i][0].ord >= 30) && (table1[i][0].ord <= 57)
s1_arr[i] = table1[i][0]
elsif (table1[i][0].ord >= 65) && (table1[i][0].ord <= 90)
s1_arr[i] = table1[i][0].ord - 64
else
s1_arr[i] = table1[i][0].ord - 96
end
end
#Loops through all of the items in the s1_arr and s0_arr and places
# an "X" on their combined position in the pos_comb array
for i in 0..((s0_arr.size)-1)
for j in 0..((s1_arr.size)-1)
if s0_arr[i] < s1_arr[j] then
#puts (s1_arr[j]-s0_arr[i]-1)
pos_comb[s0_arr[i]-1][(s1_arr[j]-s0_arr[i])-1] = "X"
else
pos_comb[s1_arr[j]-1][(s0_arr[i]-s1_arr[j])-1] = "X"
end
end
end
# #reverses the items in the pos_comb arrays
# for i in 0..((pos_comb.size)-1)
# pos_comb[i].reverse
# end
#puts pos_comb.inspect
#puts pos_comb[0][5]
#Need to go through the pos_comb array, and wherever there is not an X, fill the
#next states of the combination
#Loops through the pos_comb array, and wherever there is not an X, places an array of
#to hold the next states of the combination
for i in 0..((pos_comb.size)-1)
for j in 0..((pos_comb[i].size)-1)
if pos_comb[i][j] != "X"
pos_comb[i][j] = Array.new(4, 0)
#Places numerical form of state transitions into new array
#Columns
for k in 0 .. 1
#numbers
if (s_table[i][k+1].ord >= 30) && (s_table[i][k+1].ord <= 57)
pos_comb[i][j][k] = s_table[i][k-1]
#uppercase
elsif (s_table[i][k+1].ord >= 65) && (s_table[i][k+1].ord <= 90)
pos_comb[i][j][k] = s_table[i][k+1].ord - 64
#lowercase
else
pos_comb[i][j][k] = s_table[i][k+1].ord - 96
end
end
#Rows
for k in 2 .. 3
#numbers
#puts s_table[j].inspect
if (s_table[(i+j)+1][k-1].ord >= 30) && (s_table[(i+j)+1][k-1].ord <= 57)
pos_comb[i][j][k] = s_table[j+1][k-1]
#uppercase
elsif (s_table[(i+j)+1][k-1].ord >= 65) && (s_table[(i+j)+1][k-1].ord <= 90)
pos_comb[i][j][k] = s_table[(i+j)+1][k-1].ord - 64
#lowercase
else
pos_comb[i][j][k] = s_table[(i+j)+1][k-1].ord - 96
end
end
end
end
end
puts pos_comb.inspect
count = 0
while x_out(pos_comb, s_table).size == pos_comb.size
#pos_comb = x_out(pos_comb, s_table)
pos_comb = x_out(pos_comb, s_table)
end
puts "HERE!"
puts pos_comb.inspect
end
main()
My text document looks like the following
A B C 1
B D F 1
C F E 0
D B G 1
E F C 0
F E D 0
G F G 0
I know that the problem lies in the calling of the function, but I'm not sure how to call it the right amount of times to get the output of the properly minimized state table.
Your problem is here:
pos_comb = x_out(pos_comb, s_table)
xout
returns the value of the outer for loop
which is a range
. In ruby a for loop is an expression. For example:
x = for i in (0..5) do puts i end # x is equal to (0..5)
which is the same as
def x_out()
for i in (0..5) do puts i end
end
x = x_out() # x is equal to (0..5)
After you return from x_out
you are overwriting the value of pos_comb
with the range 0..5
. Then you pass it back into x_out
which causes your problem on the second iteration of your while
loop.
Right now it seems that you want to return arr1
from inside yourx_out
function, so try putting
...
end
arr1 # <- insert this at the last line in your function
end
at the end of your function to return arr1
instead.