Q-Learning AI Isn't Recognizing Easy Pattern - python

I have a Q-Learning program trying to predict my stock simulated stock market where the price of the stock goes 1-2-3-1-2-3...
I have been trying to debug this for a few days and just can't get it. I even completely started from scratch and the problem persists. If you have extra time, I just need an extra set of eyes on this.
The getStock() function is what simulates the stock price.
The reducePricesToBinary() function takes the stocks and makes it into an put of [Whether the stock went up or down last, how many times it went down/up in a row, how many times the stock went up/down in a row]
The readAI() function just reads what should happen given the inputs
The checkGuess() function checks the previous guess and changes the policyGradient based on whether or not it was right.
Thank you so much!
import requests
import sys
import time
# Constants
learningRate = 0.5
stocksToBuy = 250
discountFactor = 0.5
# Variables declared:
# getStock()
currentStockPrice = 0
pastStockPrice = 0
# reducePricesToBinary()
binaryVersionOfPrices = ""
# Ai()
AI = dict()
# convertBinaryToInputs()
inputsForAI = [0,0,0]
# Ai
guess = 0
oldGuess = 0
reward = 0
pastInputsForAI = ['0',0,0]
firstTurnOver = False
# Buying and Selling stocks
money = 1000000
shares = 0
#
countToSaveEveryFifteen = 0
# Saving anything to a file.
def save(name, data):
with open(name, 'w') as f:
f.write(str(data))
def saveEverything():
save("AI", AI)
save("binaryStockPrices", binaryVersionOfPrices)
save("money", money)
save("shares", shares)
# Runs after an error.
def onExit():
saveEverything()
sys.exit()
# Prints and saves an error log if a function crashes.
def crashProgram(errorMessage):
print(errorMessage)
with open("crashLogs", 'w') as f:
f.write("{}\n\n".format(errorMessage))
onExit()
# Runs a function with try catches to catch an error.
def doFunction(function):
try:
function()
except Exception, e:
crashProgram("Fatal error running {}().\n{}".format(function.__name__, e))
# Gets the current stock value.
#def getStock():
# global currentStockPrice
# res = requests.get("https://markets.businessinsider.com/stocks/aapl-stock")
# stockCostString = ""
# for x in range (9):
# stockCostString += res.text[res.text.find('"price": "')+10 + x]
# currentStockPrice = float(stockCostString)
# print(currentStockPrice)
def getStock():
global currentStockPrice
currentStockPrice = 1 if currentStockPrice == 3 else (2 if currentStockPrice == 1 else 3)
# Turns the prices into 0's and 1's.
def reducePricesToBinary():
global pastStockPrice
global binaryVersionOfPrices
binaryString = "1" if currentStockPrice > pastStockPrice else "0" if currentStockPrice < pastStockPrice else ""
binaryVersionOfPrices += binaryString
pastStockPrice = currentStockPrice
# Converts the binaryStockPrices to inputs for the AI.
def convertBinaryToInputs():
global inputsForAI
inputsForAI[0] = binaryVersionOfPrices[len(binaryVersionOfPrices)-1]
counterOfFirstNumber = 1
counterOfSecondNumber = 1
while(binaryVersionOfPrices[len(binaryVersionOfPrices) - counterOfFirstNumber] == inputsForAI[0]):
counterOfFirstNumber+=1
counterOfFirstNumber-=1
while(binaryVersionOfPrices[len(binaryVersionOfPrices) - counterOfFirstNumber - counterOfSecondNumber]!=inputsForAI[0]):
counterOfSecondNumber += 1
counterOfSecondNumber-=1
inputsForAI[0] = binaryVersionOfPrices[len(binaryVersionOfPrices)-1]
inputsForAI[1] = counterOfFirstNumber
inputsForAI[2] = counterOfSecondNumber
# AI functions
def readAI():
global guess
try:
AIGuess = AI[inputsForAI[0], inputsForAI[1], inputsForAI[2]]
except:
AI[inputsForAI[0], inputsForAI[1], inputsForAI[2]] = 0.5
AIGuess = 0.5
guess = AIGuess
print("GUESS: {}".format(guess))
print("INPUTS: {}".format(inputsForAI))
return guess
def checkGuess():
global firstTurnOver
if(firstTurnOver):
global oldGuess
global reward
global pastInputsForAI
oldGuess = 0 if oldGuess == -1 else 1
print("Old guess: " + str(oldGuess) + " Input: " + str(int(round(float(inputsForAI[0])))))
reward = 1 if oldGuess == int(round(float(inputsForAI[0]))) else -1
AI[pastInputsForAI[0], pastInputsForAI[1], pastInputsForAI[2]] = (1-learningRate) * AI[pastInputsForAI[0], pastInputsForAI[1], pastInputsForAI[2]] + learningRate * (reward + discountFactor * 1)
oldGuess = int(round(float(guess)))
pastInputsForAI = inputsForAI
firstTurnOver = True
def buySellStocks():
global money
global shares
oldStocks = shares
if(guess > 0):
while(money > currentStockPrice and (shares - oldStocks) < stocksToBuy * guess):
money -= currentStockPrice
shares += 1
else:
while(shares > 0 and (oldStocks - shares) > stocksToBuy * guess):
money += currentStockPrice
shares -= 1
# Loads the binaryVersionOfPrices from a file.
def loadBinaryPrices():
global binaryVersionOfPrices
with open("binaryStockPrices", 'r') as f:
binaryVersionOfPrices = f.read()
def loadMoney():
global money
with open("money", 'r') as f:
money = int(f.read())
def loadShares():
global shares
with open("shares", 'r') as f:
shares = int(f.read())
# Loads the AI from a file.
def loadAI():
global AI
with open("AI", 'r') as f:
AI = eval(f.read())
#Prints relative information
def printStuff():
print("Stock price: {}\nCurrent balance: {}\nCurrent shares: {}\nTotal value: {}\nGuess: {}\n".format(currentStockPrice, money, shares, money + shares * currentStockPrice, guess))
# Loads all variables from files.
def onProgramStart():
doFunction(loadAI)
doFunction(loadBinaryPrices)
doFunction(loadMoney)
doFunction(loadShares)
# Saves every 15 checks
def saveEveryFifteen():
global countToSaveEveryFifteen
countToSaveEveryFifteen += 1
if(countToSaveEveryFifteen == 15):
saveEverything()
countToSaveEveryFifteen = 0
# Runs all functions.
def doAllFunctions():
doFunction(reducePricesToBinary)
doFunction(convertBinaryToInputs)
doFunction(readAI)
doFunction(checkGuess)
doFunction(buySellStocks)
doFunction(saveEveryFifteen)
doFunction(printStuff)
doFunction(getStock)
# Loads variables from files.
onProgramStart()
# Repeats the process.
while(1):
doAllFunctions()
time.sleep(0.5)

As I mentioned in my comment, here is a version of the program after some basic refactoring:
import sys
import time
# constants
learning_rate: float = 0.5
stocks_to_buy: float = 250
discount_factor: float = 0.5
# variables declared:
# get_stock()
current_stock_price: int = 0
past_stock_price: int = 0
# reduce_prices_to_binary()
binary_version_of_prices: str = ''
# ai()
a_i: dict = {}
# convert_binary_to_inputs()
inputs_for_a_i = [0, 0, 0]
# ai
guess = 0
old_guess = 0
reward = 0
past_inputs_for_a_i = ['0', 0, 0]
first_turn_over: bool = False
# buying and selling stocks
money: int = 1000000
shares: int = 0
#
count_to_save_every_fifteen: int = 0
# saving anything to a file.
def save(name, data):
with open(name, 'w') as f:
f.write(str(data))
def save_everything():
save("a_i", a_i)
save("binary_stock_prices", binary_version_of_prices)
save("money", money)
save("shares", shares)
# runs after an error.
def on_exit():
save_everything()
sys.exit()
# gets the current stock value.
# def get_stock():
# global current_stock_price
# res = requests.get("https://markets.businessinsider.com/stocks/aapl-stock")
# stock_cost_string = ""
# for x in range (9):
# stock_cost_string += res.text[res.text.find('"price": "')+10 + x]
# current_stock_price = float(stock_cost_string)
# print(current_stock_price)
def get_stock():
global current_stock_price
if current_stock_price == 3:
current_stock_price = 1
elif current_stock_price == 1:
current_stock_price = 2
else:
current_stock_price = 3
# turns the prices into 0's and 1's.
def reduce_prices_to_binary():
global past_stock_price
global binary_version_of_prices
if current_stock_price > past_stock_price:
binary_string = "1"
elif current_stock_price < past_stock_price:
binary_string = "0"
else:
binary_string = ""
binary_version_of_prices += binary_string
past_stock_price = current_stock_price
# converts the binary_stock_prices to inputs for the a_i.
def convert_binary_to_inputs():
global inputs_for_a_i
inputs_for_a_i[0] = binary_version_of_prices[len(binary_version_of_prices) - 1]
counter_of_first_number = 1
counter_of_second_number = 1
while binary_version_of_prices[len(binary_version_of_prices) - counter_of_first_number] == inputs_for_a_i[0]:
counter_of_first_number += 1
counter_of_first_number -= 1
while (binary_version_of_prices[
len(binary_version_of_prices) - counter_of_first_number - counter_of_second_number] !=
inputs_for_a_i[0]):
counter_of_second_number += 1
counter_of_second_number -= 1
inputs_for_a_i[0] = binary_version_of_prices[len(binary_version_of_prices) - 1]
inputs_for_a_i[1] = counter_of_first_number
inputs_for_a_i[2] = counter_of_second_number
# a_i functions
def read_ai():
global guess
try:
a_i_guess = a_i[inputs_for_a_i[0], inputs_for_a_i[1], inputs_for_a_i[2]]
except:
a_i[inputs_for_a_i[0], inputs_for_a_i[1], inputs_for_a_i[2]] = 0.5
a_i_guess = 0.5
guess = a_i_guess
print(f'guess: {guess}')
print(f'inputs: {inputs_for_a_i}')
return guess
def check_guess():
global first_turn_over
if first_turn_over:
global old_guess
global reward
global past_inputs_for_a_i
old_guess = 0 if old_guess == -1 else 1
print(f'old guess: {old_guess}, input: {round(float(inputs_for_a_i[0]))}')
if old_guess == round(float(inputs_for_a_i[0])):
reward = 1
else:
reward = -1
a_i[past_inputs_for_a_i[0], past_inputs_for_a_i[1], past_inputs_for_a_i[2]] = (1 - learning_rate) * a_i[
past_inputs_for_a_i[0], past_inputs_for_a_i[1], past_inputs_for_a_i[2]] + learning_rate * (
reward + discount_factor * 1)
old_guess = int(round(float(guess)))
past_inputs_for_a_i = inputs_for_a_i
first_turn_over = True
def buy_sell_stocks():
global money
global shares
old_stocks = shares
if guess > 0:
while money > current_stock_price and (shares - old_stocks) < stocks_to_buy * guess:
money -= current_stock_price
shares += 1
else:
while shares > 0 and (old_stocks - shares) > stocks_to_buy * guess:
money += current_stock_price
shares -= 1
# loads the binary_version_of_prices from a file.
def load_binary_prices():
global binary_version_of_prices
with open("../resources/ai_stock_files/binary_stock_prices", 'r') as f:
binary_version_of_prices = f.read()
def load_money():
global money
with open("../resources/ai_stock_files/money") as f:
money = int(f.read())
def load_shares():
global shares
with open("../resources/ai_stock_files/shares") as f:
shares = int(f.read())
# loads the _a_i from a file.
def load_a_i():
global a_i
with open("../resources/ai_stock_files/a_i") as f:
a_i = eval(f.read())
# prints relative information
def print_stuff():
print(f"stock price: {current_stock_price}\n"
f"current balance: {money}\n"
f"current shares: {shares}\n"
f"total value: {money + shares * current_stock_price}\n"
f"guess: {guess}\n")
# loads all variables from files.
def on_program_start():
load_a_i()
load_binary_prices()
load_money()
load_shares()
# saves every 15 checks
def save_every_fifteen():
global count_to_save_every_fifteen
count_to_save_every_fifteen += 1
if count_to_save_every_fifteen == 15:
save_everything()
count_to_save_every_fifteen = 0
# runs all functions.
def do_all_functions():
reduce_prices_to_binary()
convert_binary_to_inputs()
read_ai()
check_guess()
buy_sell_stocks()
save_every_fifteen()
print_stuff()
get_stock()
# loads variables from files.
on_program_start()
# repeats the process.
while True:
do_all_functions()
time.sleep(0.5)

When correcting the policies in the policy gradient, I was using inputs from a cycle ago and over compensating by calling the functions in an order where it already used inputs from a cycle ago, effectively making the gradient off by two inputs. Since I was cycling the input in 3's it made it look like an "off-by-one" error when in reality I was off by two, making it hard to detect.

Related

Fix python terminal not showing output

When I run the main or eqparse file, the python terminal will not show any output. This applies to both the command prompt and visual studio code.
Here is my code from the main file. I am including some of the likely unrelated stuff just in case. It is labeled so you can skip all the potentially unrelated stuff.
from graphics import *
from eqparse import *
# NOTE: For equation mapping, it will input a string and convert the data to a table.
# After, you take in the table coords and map each point
# dump vars here #
xypm = 0
global patternFind
global count
global indexlist
# profile initialization #
def init(name, nxsize, nysize, noffset, nzoom):
global zoom
zoom = nzoom
global xsize
xsize = nxsize
global eqtype
eqtype = bool(1)
global ysize
ysize = nysize
global win
win = GraphWin(name, nxsize, nysize)
global offset
offset = noffset
global xymark
xymark = (nzoom * -1)/2
global txsize
txsize = nxsize/2
global tysize
tysize = nysize/2
global txymark
txymark = xymark * -1 + 1
global xp1
xp1 = Point(xypm,(txsize) + offset)
global yp1
yp1 = Point((tysize) + offset, xypm)
global xp2
xp2 = Point(xypm,(txsize) - offset)
global yp2
yp2 = Point((tysize) - offset, xypm)
# starting procedure #
def startUp():
# xy lines #
global xymark
global xp1
global xp2
global yp1
global yp2
global xypm
xtrace = Line(Point(0,tysize), Point(xsize,tysize))
ytrace = Line(Point(txsize,0), Point(txsize,ysize))
xtrace.draw(win)
ytrace.draw(win)
# grid drawer #
while xymark < txymark:
txline = Line(xp1, xp2)
tyline = Line(yp1, yp2)
txline.draw(win)
tyline.draw(win)
xypm = xypm + xsize/zoom
xp1 = Point(xypm,(tysize) + offset)
yp1 = Point((txsize) + offset, xypm)
xp2 = Point(xypm,(tysize) - offset)
yp2 = Point((txsize) - offset, xypm)
xymark = xymark + 1
# code for ending mark #
Line(Point(txsize - offset, ysize - 1), Point(txsize + offset, ysize - 1)).draw(win)
Line(Point(xsize - 1,tysize - offset), Point(xsize - 1, tysize + offset)).draw(win)
# point drawing #
def drawCo(nx, ny):
pCircle = Circle(Point(xsize/zoom * (nx) + xsize/2, ysize - (ysize/zoom * (ny) + ysize/2)), 3)
pCircle.setFill("black")
pCircle.draw(win)
# main #
print("Checkpoint 1")
init("test",500, 500, 10, 20)
print("Checkpoint 2")
startUp()
print("Checkpoint 3")
drawCo(3,5)
print("Checkpoint 4")
patternFind("Dung","DungBeatlesbeingadungbeetle")
print("Checkpoint 5")
print(count)
print("Checkpoint 6")
for x in range(len(indexlist)):
print(indexlist[x])
print("Checkpoint 7")
# exit function #
win.getMouse()
win.close()
and the eqparse file:
# eqparse will look for certain patterns in strings, generate an equation,
# and create a table that a drawing function can read
from main import *
global indexlist
global count
global patternFind
global convStr
# convert string to valid equation data
def convStr(input):
if input[0] == 'y':
print("Linear")
elif input[0] == 'r':
print("Polar")
else:
print("Use Equation type on left side")
# subroutine that will be used to find patterns in a sequence #
def patternFind(pattern, input):
indexlist = []
count = 0
l = len(pattern)
tstr =""
if l > len(input):
pass
else:
i = 0
j = len(input) - len(pattern) + 1
k=0
while j > 0:
tstr = ""
i=0
while len(tstr) < l:
tstr = tstr + input[i + k]
i = i + 1
if tstr == pattern:
count = count + 1
indexlist.append(i+k)
else:
continue
j = j - 1
k=k+1
The output when I run main:
Checkpoint 1
Checkpoint 2
Checkpoint 3
Checkpoint 4
(also the window that I run lags out)
On a related note: When I use the standard import syntax nothing happens. I have to use from (file) import * for it to work.
Yor problem is in def patternFind()
in Your second while loop your counter k and j is never increasing.
So you have a infinite loop.
your code never go beyond the continue statement and stuck there forever.
But maybe you can replace that whole function with a python built-in:
def patternFind(pattern, input):
return pattern in input #true if pattern is in the input

Python program exits immediately after start

given the following code (in python):
import random
import sys
import collections
commandStr = ["addClan", "addPlayer",
"clanFight", "getMinClan"]
SUCCESS = "SUCCESS"
FAILURE = "FAILURE"
INVALID_INPUT = "INVALID_INPUT"
ClanID = dict()
playersID = dict()
ClanScore = collections.defaultdict(list)
playersClan = dict()
LosingClans = set()
Clans_count = 0;
players_count = 0;
def initline():
global ClanID, Clans_count
inLine = "init 2 0 1"
outLine = "init done."
ClanID[0] = {}
ClanID[1] = {}
Clans_count += 2
return inLine, outLine
# addClan clanID
def addClan():
global ClanID, Clans_count
clanID = random.randint(-2, 8)
inLine = "addClan %d" % (clanID)
outLine = "addClan: "
if clanID < 0:
outLine += INVALID_INPUT
elif clanID in ClanID.keys():
outLine += FAILURE
else:
ClanID[clanID] = {}
Clans_count += 1
outLine += SUCCESS
return inLine, outLine
# addPlayer playerID score clanID
def addPlayer():
global playersID, ClanID, ClanScore, playersClan, players_count
playerID = random.randint(-10, 1000)
score = random.randint(-10, 1000)
clanID = random.randint(-2, 8)
inLine = "addPlayer %d %d %d" % (playerID, score, clanID)
outLine = "addPlayer: "
if playerID < 0 or clanID < 0 or score <0:
outLine += INVALID_INPUT
elif playerID in playersID.keys() or clanID not in ClanID.keys():
outLine += FAILURE
else:
playersID[playerID] = playerID
if clanID in ClanScore.keys():
ClanScore[clanID].append(score)
else:
ClanScore[clanID] = [score]
playersClan[playerID] = clanID
ClanID[clanID][playerID] = (playersID[playerID], clanID)
players_count += 1
outLine += SUCCESS
return inLine, outLine
# getMinClan
def getMinClan():
global ClanID, LosingClans
inLine = "getMinClan"
outLine = "getMinClan: "
for Clan_id in sorted(ClanID):
if Clan_id not in LosingClans:
outLine += SUCCESS + " %d" % Clan_id
break
return inLine, outLine
def sum_n_strongest(Clan, num):
sortedClan = sorted(Clan, reverse=True)
topNum = sortedClan[:num]
Sum = 0
for element in topNum:
Sum += element
return Sum
# clanFight clan1 clan2 k1 k2
def clanFight():
global ClanID, ClanScore, LosingClans
clan1 = random.randint(-1, 8)
clan2 = random.randint(-1, 8)
k1 = random.randint(-1, 10)
k2 = random.randint(-1, 10)
inLine = "clanFight %d %d %d %d" % (clan1, clan2, k1, k2)
outLine = "clanFight: "
if k1 <= 0 or k2 <= 0 or clan1 < 0 or clan2 < 0:
outLine += INVALID_INPUT
elif clan1 not in ClanID.keys() or clan2 not in ClanID.keys() or clan1 == clan2 or len(ClanID[clan1]) < k1 or len(ClanID[clan2]) < k2:
outLine += FAILURE
elif clan1 in LosingClans or clan2 in LosingClans:
outLine += FAILURE
else:
sum1 = sum_n_strongest(ClanScore[clan1], k1)
sum2 = sum_n_strongest(ClanScore[clan2], k2)
if sum1 == sum2:
if clan1 < clan2:
LosingClans.add(clan2)
else:
LosingClans.add(clan1)
elif sum1 < sum2:
LosingClans.add(clan1)
else:
LosingClans.add(clan2)
outLine += SUCCESS
return inLine, outLine
def main():
if len(sys.argv) < 3:
print("Usage %s <lines>" % sys.argv[0])
exit(0)
lines = int(sys.argv[1])
infname = "%s.in" % sys.argv[2]
outfname = "%s.out" % sys.argv[2]
functions = [addClan, addPlayer,
getMinClan, clanFight]
with open(infname, 'wb') as infhandler:
with open(outfname, 'wb') as outfhandler:
inLine, outLine = initline()
infhandler.write(inLine + "\n")
outfhandler.write(outLine + "\n")
while lines > 0:
f = random.randint(0, len(functions)-1)
func = functions[f]
inLine, outLine = func()
if inLine is not "":
infhandler.write(inLine + "\n")
outfhandler.write(outLine + "\n")
lines -= 1
infhandler.write("quit\n")
outfhandler.write("quit done.\n")
main()
This code should create a new file while I need to give as parameters filename and numberOfLines.
But, while I trying to run this script, opened to me a black window (like a cmd) and it's closed immediately.
How can I fix it? someone know what is the problem?
Note: this code written me in a file which his name is "Test.py" , and I trying to run it with this line command: python ./Test.py <Number of Lines> <Test Name> (at least, I trying to do it while I double-click about "Test.py" but like that I said, the window closed immediately..
Follow-up question: Are you using an IDE, or are you trying to run this from the command line/command prompt?
First, check if the files exist after you run the program. It might just be that the program is running quickly enough that it only takes a couple milliseconds, and the command prompt goes away once the program terminates. If it does create a file, the program wouldn't outwardly notify you; look in your file directory and see if it did.
Second, instead of just calling main() at the end of your file, maybe try:
if __name__ == "__main__":
main()
and see if anything different happens. This bit of code is executed whenever the file is run as specifically as a script (as you're doing with the command % python Test.py <num> <fname>).

Python error: int object has no attribute to append?

I can't figure out why my code isn't working, very frustrating. I constantly get the error: int object has no attribute to append (for average.append(i, average//250)). But I can't figure out what exactly is wrong here. Is it not possible to import other definition in append functions?
I hope somebody can help me out!
Any help with my code in general is appreciated :)
def main():
average = []
y_values = []
for x in range(0, 2501, 500):
for i in range(250):
average.append(calculate(x))
average = sum(average)
print("{} euro, {} worpen".format(i, average//250))
y_values.append(average//250)
x_values = [0, 500, 1000, 1500, 2000, 2500]
y_values = []
plt.plot(x_values, y_values)
plt.xlabel("Startgeld")
plt.ylabel("Aantal worpen")
plt.title("Monopoly")
plt.show()
def calculate(game_money):
piece = monopoly.Piece()
board = monopoly.Board()
owns = possession(board)
dice = throw()
throw_count = 0
number = 0
total_throw = 0
while not all(owns.values()):
number == throw()
piece.move(number)
total_throw = total_throw + number
throw_count += 1
if total_throw > 40:
game_money += 200
elif board.values[piece.location] > 0:
if game_money > board.values[piece.location]:
if owns[board.names[piece.location]] == False:
owns[board.names[piece.location]] = True
game_money = game_money - board.values[piece.location]
return total_throw
def throw():
dice = randint(1,6) + randint(1,6)
return dice
def possession(board):
owns = {}
for i in range(40):
if board.values[i] > 0:
owns[board.names[i]] = False
return owns
if __name__ == "__main__":
main()
You done a small mistake in your code. See my comment below and correct your code accordingly. Good Luck :-)
y_values = []
average = []
for x in range(0, 2501, 500):
for i in range(250):
average.append(calculate(x))
#average = sum(average) #This is your mistake. Now onward average will be considered as int object make it like below
average1 = sum(average)
print("{} euro, {} worpen".format(i, average1//250))
y_values.append(average1//250)

Python stuck in a single thread of a multi-threaded program

I'm currently writing a program that is attempting to synchronize a visitor, car, pump, and gas station thread at a zoo where guests arrive, wait for an available car, take a tour, then exit, the cars must refuel every 5 rides, and the gas station must refuel every time 3 cars are refilled. My tests are with 35 visitors, 6 cars, 5 gas pumps, and a time interval of 2. The program reads a text file with the number of guests, cars, pumps, and a time interval between visitors boarding vehicles, then uses the data to fill a class. I create methods for each thread, then create the threads themselves in main. My problem is that my program gets stuck at 6 vehicles, which is the number specified by the text file, after running my first thread method, visitor_thread, and I cannot tell if any other threads are even running concurrently. I am a total novice at multithreading and python alike, and I'm not sure what the problem is. I have worked on the project for twelve hours straight and have been stuck at this point for the past four hours. In theory, visitor_thread, car_thread, and gas_station_thread should all run concurrently from main, and visitor_thread should have vehicles to work with again after some visitors finish their ride, but I just get stuck with six full cars in an infinite loop within visitor_thread. What is causing this infinite loop and how can I make sure all of my threads are actually running?
My code:
from threading import Thread
from threading import Lock
from threading import Event
event = Event()
lock = Lock()
done = Event()
is_done = 0
class Arguments:
def __init__(self, m_visitors, n_cars, k_pumps, t_time, thread_num, _done):
self.m_visitors = m_visitors
self.n_cars = n_cars
self.k_pumps = k_pumps
self.t_time = t_time
self.thread_num = thread_num
self.done = _done
class Car:
def __init__(self, control, rides, time, in_service, int_cus, in_queue):
self.control = control
self.rides = rides
self.time = time
self.in_service = in_service
self.int_cus = int_cus
self.in_queue = in_queue
class Pump:
def __init__(self, control, in_use, car_num, time):
self.control = control
self.in_use = in_use
self.car_num = car_num
self.time = time
class PumpQueue:
def __init__(self, pQueue, MAXsize, front, back, size):
self.q = Lock()
self.pQueue = pQueue
self.MAXsize = MAXsize
self.front = front
self.back = back
self.size = size
def visitor_thread(_visitor):
global is_done
visitor = _visitor
v = visitor.m_visitors
c = visitor.n_cars
p = visitor.k_pumps
t = visitor.t_time
id = visitor.thread_num
i = 0
j = 0
while i < v:
for j in range(0, c):
lock.acquire()
if cars[j].in_service is False and cars[j].rides < 5:
print('\nVisitor %d is currently in car %d' % (i+1, j+1))
cars[j].in_service = True
i += 1
print('\n%d customers waiting for a ride.' % (v - i))
lock.release()
break
lock.release()
lock.acquire()
is_done += 1
lock.release()
def car_thread(_car):
global is_done
carThread = _car
cars_done = 0
v = carThread.m_visitors
c = carThread.n_cars
p = carThread.k_pumps
t = carThread.t_time
id = carThread.thread_num
i = 0
while cars_done == 0:
cars_in_service = 0
while i < c:
lock.acquire()
if cars[i].in_service is True and cars[i].rides < 5:
# Car still being used, add more time
cars[i].time += 1
if cars[i].time == t:
cars[i].in_service = False
cars[i].rides += 1
cars[i].time = 0
if cars[i].rides == 5 and cars[i].in_queue is False:
push(i)
cars[i].in_queue = True
if cars[i].in_service is False:
cars_in_service += 1
i += 1
lock.release()
if cars_in_service == c and is_done >= 1:
cars_done = 1
lock.acquire()
is_done += 1
lock.release()
def gas_station_thread(_gas_station):
global is_done
gas_station = _gas_station
truck = False
cars_filled = 0
v = gas_station.m_visitors
c = gas_station.n_cars
p = gas_station.k_pumps
t = gas_station.t_time
id = gas_station.thread_num
gas_done = 0
pumps_in_service = 0
j = 0
while gas_done == 0:
while j < p:
lock.acquire()
if pumps[j].in_use is True:
pumps[j].time += 1
if pumps[j].time == 3:
lock.acquire()
cars[j].in_service = 0
cars[j].rides = 0
cars[j].time = 0
cars[j].in_queue = False
lock.release()
pumps[j].time = 0
pumps[j].in_use = False
cars_filled += 1
pumps_in_service -= 1
if truck is True and pumps[j].in_use is False:
truck = False
print('Fuel Truck is currently filling up the gas station.')
elif pumps[j].in_use is True and pump_line.size > 0:
pumps_in_service += 1
pumps[j].in_use = True
pumps[j].car_num.pop()
print('Car %d, pump %d' % (pumps[j].car_num + 1, i + 1))
pumps[j].time = 0
j += 1
lock.release()
if cars_filled > 3:
print('The Fuel Truck is on its way')
truck = True
cars_filled = 0
if pumps_in_service == 0 and is_done == 2:
gas_done = True
lock.acquire()
is_done += 1
lock.release()
def pop():
lock.acquire()
fr = pump_line.front
f = pump_line.pQueue[fr]
print("\n%d cars are waiting for pumps" % int(pump_line.size - 1))
if fr < (pump_line.MAXsize - 1):
pump_line.front += 1
else:
pump_line.front = 0
lock.release()
return f
def push(_c):
c =_c
lock.acquire()
b = pump_line.back
pump_line.pQueue[b] = c
print("\n%d cars are waiting for pumps" % int(pump_line.size + 1))
if b < (pump_line.MAXsize - 1):
pump_line.back += 1
else:
pump_line.back = 0
lock.release()
def isEmpty():
lock.acquire()
if (pump_line.front == pump_line.back):
boolean = True
else:
boolean = False
lock.release()
return boolean
if __name__ == "__main__":
arguments = Arguments(0, 0, 0, 0, 0, False)
main = Arguments(0, 0, 0, 0, 0, False)
thread = []
round_number = 0
io_control = 0
input_file = []
number_of_threads = 3
print("Enter the name of the text file to use as input:")
while io_control == 0:
try:
filename = input()
input_file = open(filename)
io_control = 1
except IOError:
print("Specified file does not exist, enter a different text file:")
# parse file into lines, separating by endlines
file_lines = []
num_lines = 0
for line in input_file:
line = line.replace(",", " ")
line = line.split()
num_lines += 1
if line:
line = [int(i) for i in line]
file_lines.append(line)
while main.done is False and round_number < num_lines:
main.m_visitors = int(file_lines[round_number][0])
main.n_cars = int(file_lines[round_number][1])
main.k_pumps = int(file_lines[round_number][2])
main.t_time = int(file_lines[round_number][3])
print("\nRound Number: %d" % (round_number + 1))
if main.n_cars == 0:
print('No data to read in this round, press enter to continue:')
input()
print("Number of Visitors: %d" % main.m_visitors)
print("Number of Cars: %d" % main.n_cars)
print("Number of Pumps: %d" % main.k_pumps)
print("Units of Time: %d" % main.t_time)
M = main.m_visitors
N = main.n_cars
K = main.k_pumps
T = main.t_time
thread_info = []
cars = []
pumps = []
for i in range(0, 3):
temp = Arguments(M, N, K, T, i, False)
thread_info.append(temp)
for i in range(0, N):
temp = Car(0, 0, 0, False, 0, False)
cars.append(temp)
for i in range(0, K):
temp = Pump(0, False, 0, 0)
pumps.append(temp)
pump_line = PumpQueue(0, 0, 0, 0, N)
visitorThread = Thread(target=visitor_thread, args=(thread_info[0],))
thread.append(visitorThread)
carsThread = Thread(target=car_thread, args=(thread_info[1],))
thread.append(carsThread)
gasThread = Thread(target=gas_station_thread, args=(thread_info[2],))
thread.append(gasThread)
visitorThread.start()
carsThread.start()
gasThread.start()
visitorThread.join()
carsThread.join()
gasThread.join()
round_number += 1
My output:
Round Number: 1 Number of Visitors: 35 Number of Cars: 6 Number of
Pumps: 5 Units of Time: 2
Visitor 1 is currently in car 1
34 customers waiting for a ride.
Visitor 2 is currently in car 2
33 customers waiting for a ride.
Visitor 3 is currently in car 3
32 customers waiting for a ride.
Visitor 4 is currently in car 4
31 customers waiting for a ride.
Visitor 5 is currently in car 5
30 customers waiting for a ride.
Visitor 6 is currently in car 6
29 customers waiting for a ride.
I think there's an index problem here:
if cars[j].in_service is False and cars[i].rides < 5:
should be
if cars[j].in_service is False and cars[j].rides < 5:
Index for cars is j not i

Genetic algorithm suspends in python?

I have implemented a simple genetic algorithm in python - here is the most of the code:
import random
ings = (('w1', 200, 25, 80),
('su1', 50, 55, 150),
('su2', 400, 100, 203),
('sy1', 10, 150, 355),
('sy2', 123, 88, 101),
('sy3', 225, 5, 30),
('sy4', 1, 44, 99),
('sy5', 500, 220, 300))
mutationRate = 0.2
crossoverRate = 0.9
iterations = 100
file = open('D:\\logfile2.txt', 'a')
class Ingredient:
def __init__(self, n, p, mi, ma):
self.name = n
self.price = p
self.min = mi
self.max = ma
self.perc = random.randrange(self.min, self.max)
class Drink:
def __init__(self):
self.ing = [Ingredient(*x) for x in ings]
self.normalize()
self.fitness = self.evaluate()
def normalize(self):
sum = 0
for x in self.ing:
sum += x.perc
if sum < 1000:
offset = 1000 - sum
while not offset == 0:
index = random.randrange(len(self.ing))
val = self.ing[index].max - self.ing[index].perc
threshold = random.randrange(val) if val > 0 else 0
threshold = threshold if threshold < offset else offset
self.ing[index].perc += threshold
offset -= threshold
if sum > 1000:
offset = sum - 1000
while not offset == 0:
index = random.randrange(len(self.ing))
val = self.ing[index].perc - self.ing[index].min
threshold = random.randrange(val) if val > 0 else 0
threshold = threshold if threshold < offset else offset
self.ing[index].perc -= threshold
offset -= threshold
def evaluate(self):
fitness = 0
for x in self.ing:
fitness += x.perc * x.price
return 300000 - fitness
class GeneticAlgorithm:
def __init__(self):
self.drinkList = [Drink() for x in range(8)]
self.pool = []
def mutate(self, index):
ing1, ing2 = random.randrange(8), random.randrange(8)
while ing1 == ing2:
ing2 = random.randrange(8)
ptr = self.drinkList[index].ing
ing1thr = ptr[ing1].max - ptr[ing1].perc
ing2thr = ptr[ing2].perc - ptr[ing2].min
if ing1thr & ing2thr:
change = random.randrange(ing1thr if ing1thr < ing2thr else ing2thr)
ptr[ing1].perc += change
ptr[ing2].perc -= change
def crossover(self, index1, index2):
ing1, ing2 = random.randrange(8), random.randrange(8)
while ing1 == ing2:
ing2 = random.randrange(8)
ptr1 = self.drinkList[index1].ing[:]
ptr2 = self.drinkList[index2].ing[:]
resultIndex1 = random.randrange(len(self.drinkList))
while True:
resultIndex2 = random.randrange(len(self.drinkList))
if not resultIndex1 == resultIndex2:
break
bias = 1 if ptr1[ing1].perc > ptr2[ing1].perc else -1
if bias == 1:
maxChange = min(ptr1[ing1].perc - ptr1[ing1].min,
ptr1[ing2].max - ptr1[ing2].perc,
ptr2[ing1].max - ptr2[ing1].perc,
ptr2[ing2].perc - ptr2[ing2].min)
if maxChange:
change = random.randrange(maxChange)
ptr1[ing1].perc -= change
ptr1[ing2].perc += change
ptr2[ing1].perc += change
ptr2[ing2].perc -= change
self.drinkList[resultIndex1].ing = ptr1[:]
self.drinkList[resultIndex2].ing = ptr2[:]
if bias == -1:
maxChange = min(ptr1[ing1].max - ptr1[ing1].perc,
ptr1[ing2].perc - ptr1[ing2].min,
ptr2[ing1].perc - ptr2[ing1].min,
ptr2[ing2].max - ptr2[ing2].perc)
if maxChange:
change = random.randrange(maxChange)
ptr1[ing1].perc += change
ptr1[ing2].perc -= change
ptr2[ing1].perc -= change
ptr2[ing2].perc += change
self.drinkList[resultIndex1].ing = ptr1[:]
self.drinkList[resultIndex2].ing = ptr2[:]
def roulette(self):
sum = 0
lst = []
for x in self.drinkList:
sum += x.fitness
lst.append(sum)
return lst
def selectOne(self):
selection = random.randrange(self.pool[-1])
index = 0
while selection >= self.pool[index]:
index += 1
return index
def selectCouple(self):
selection1 = random.randrange(self.pool[-1])
index1, index2 = 0, 0
while selection1 >= self.pool[index1]:
index1 += 1
while True:
selection2 = random.randrange(self.pool[-1])
while selection2 >= self.pool[index2]:
index2 += 1
if not index1 == index2: break
return (index1, index2)
def save(self, text):
file.write(text)
for x in self.drinkList:
for y in x.ing:
file.write('min: ' + str(y.min) +
' max: ' + str(y.max) +
' value: ' + str(y.perc) + '\n')
file.write('\n\n')
file.write('\nPopulation fitness: ' +
str(self.calculatePopulationFitness()) +
'\n\n----------------------------------------------\n\n')
def run(self):
file.write("Genetic algorithm\n\nAttributes values:\n" +
"Mutation rate: " + str(mutationRate) +
"\nCrossover rate: " + str(crossoverRate) +
"\nIterations: " + str(iterations) +
"\nIngredients:\n\n" + str(ings))
self.save('\n\n--First population--\n\n')
for cnt in range(iterations):
self.updateFitness()
self.pool = self.roulette()
if random.random() < mutationRate:
index = self.selectOne()
self.showFitness('Mutation in iteration ' + str(cnt))
self.mutate(index)
self.updateFitness()
self.showFitness('Results: ')
if random.random() < crossoverRate:
index1, index2 = self.selectCouple()
self.showFitness('Crossover in iteration ' + str(cnt))
self.crossover(index1, index2)
self.updateFitness()
self.showFitness('Results: ')
self.save('--Final population--\n\n')
def calculatePopulationFitness(self):
sum = 0
for x in self.drinkList:
sum += x.fitness
return sum
def updateFitness(self):
for x in self.drinkList:
x.fitness = x.evaluate()
def showFitness(self, text):
lst = [x.fitness for x in self.drinkList]
all = sum(lst)
file.write(text + '\n' + str(lst) + '||' + str(all) + '\n')
To run it I create an instance of GeneticAlgorithm and launch it through run() method.
The problem is, for low level of iterations the program works more or less fine, but if I set iteration to 50 for example, it seems to fall in infinite loop or suspend at random iteration (the logfile is not updated anymore and the program does not stop - happenes at random iteration). What can be the cause of this?
PS: Can you suggest any changes to the coding style? I'm quite new to python and i don't know all the conventions yet.
I don't completely understand your algorithm but it looks like your code hangs in this loop here:
while True:
selection2 = random.randrange(self.pool[-1])
while selection2 >= self.pool[index2]:
index2 += 1
if not index1 == index2: break
It gets to a point where you never get a value where index1 != index2. This could either indicate you have a mistake somewhere in your code, or that there isn't a situation that meets this condition. You could try putting a cap on the number of iterations of this, for example:
iters = 0
while iters < 5000:
selection2 = random.randrange(self.pool[-1])
while selection2 >= self.pool[index2]:
index2 += 1
iters += 1
if index1 != index2: break
if iters == 5000:
# Deal with not being able to identify a Couple
I know the question is more than a year old. Still I wanted a GA code in python to start with and found the problem.
while True:
selection2 = random.randrange(self.pool[-1])
while selection2 >= self.pool[index2]:
index2 += 1
if not index1 == index2: break
The problem is in this loop. once index2 is found to be equal it is not reset back to zero before trying to find a new value.
while True:
index2 = 0
selection2 = random.randrange(self.pool[-1])
while selection2 >= self.pool[index2]:
index2 += 1
if not index1 == index2: break

Categories