Python Scheduling Algorithm - python

I am writing a scheduling algorithm for testing purposes and following the "Introduction to Algorithm book", but this is as far as I can get. As of now the job is dying in the weed "Endless loop somewhere". Generally, the algorithm should have a profit and we sort all other arrays according to profit "But I am just ignoring that for now" and my inputs are already sorted. So, the deadline and jobs passed are already sorted. Need somehelp as its still not working.
#!/usr/bin/python3.6
class Scheduling:
def schedule(self, n, deadline, jobs):
self.fdeadline = deadline
self.J = []
self.J.append(jobs[0])
self.i = 1
while self.i <= n:
self.K = self.J.copy()
self.K.append(jobs[self.i])
self.i = self.i + 1
if self.feasible(self.K, self.fdeadline) == True :
self.J = self.K
return self.J
def feasible(self, K, fdl):
self.tmp = K
self.isFeasible = True
self.i = 0
self.j = 1
self.k = 0
while self.i < len(self.tmp):
while self.j < len(self.tmp):
self.index1 = self.i
self.index2 = self.j
if (fdl[self.index1] > fdl[self.index2]):
self.tmp[i], self.tmp[j] = self.tmp[j], self.tmp[i]
while self.k < len(self.tmp):
self.job = self.tmp[self.k]
if (fdl[self.job] < k + 1):
isFeasible = False
break
return isFeasible
def main():
sins = Scheduling()
n = 4
deadline = [1,1,2,2]
jobs = [4, 2, 1, 3]
sjobs = sins.schedule(n, deadline, jobs)
print (sjobs)
if __name__ == "__main__":
main()

Here is a fully functioning code to the scheduling, it might need some small refinements, but its working fine.
#!/usr/bin/python3.6
from operator import itemgetter
class Scheduling:
def __init__(self, jobs):
self.jobs = jobs
def schedule(self, n, deadline):
self.sdl = deadline
self.J = []
self.J.append(self.jobs[1])
self.x = 2
while self.x < n:
self.K = self.J.copy()
self.K.append(self.jobs[self.x])
self.x = self.x + 1
self.feasibility = self.feasible(self.K, self.sdl)
if self.feasibility == True:
self.J = self.K.copy()
return self.J
def feasible(self, K, fdl):
self.tmp = K
self.isFeasible = True
self.i = 0
self.j = 1
self.k = 0
while self.i < len(self.tmp):
while self.j < len(self.tmp):
self.index1 = self.jobs.index(self.tmp[self.i])
self.index2 = self.jobs.index(self.tmp[self.j])
self.j = self.j + 1
if (fdl[self.index1] > fdl[self.index2]):
self.tmp[self.i], self.tmp[self.j] = self.tmp[self.j], self.tmp[self.i]
self.i = self.i + 1
while self.k < len(self.tmp):
self.job = self.tmp[self.k]
self.jobindex = self.jobs.index(self.job)
self.dlineval = fdl[self.jobindex]
self.ftest = self.k + 1
self.k = self.k + 1
if (self.dlineval < self.ftest):
self.isFeasible = False
break
return self.isFeasible
def main():
n = 7
jobs = [0, 1, 2, 3, 4, 5, 6]
deadline = [0, 2, 4, 3, 3, 2, 1]
profit = [0 , 46, 52, 30, 36 ,56, 40]
midresult = [list(x) for x in zip(deadline, profit ,jobs)]
midresult.sort(key=lambda k: (k[0], -k[1]))
deadline, profit, jobs = map(list, zip(*midresult))
sins = Scheduling(jobs)
sjobs = sins.schedule(n, deadline)
print("\n Jobs", sjobs)
finalprofit = []
finaldl = []
for c in range(len(sjobs)):
item = sjobs[c]
jobsindex = jobs.index(item)
finalprofit.append(profit[jobsindex])
finaldl.append(deadline[jobsindex])
print("\n profit", finalprofit)
print("\n Deadline", finaldl)
if __name__ == "__main__":
main()

First of all understand self in python. Read link
Secondly understand the job sequencing problem. Read link
Then, look at the below code
class Scheduling:
def schedule(self, n, deadline, jobs):
# max number of jobs you can schedule is the max deadline available.
filledJobs = ['dummy']*max(deadline);
i = 0
# start assigning the jobs in a greeedy way
while i < n:
job = jobs[i]
j = deadline[i]
# assign the job from the last deadline
while j > 0:
if(filledJobs[j-1] == 'dummy'):
filledJobs[j-1] = job
break
j = j - 1
i = i + 1
return filledJobs
def main():
sins = Scheduling()
n = 4
deadline = [1,1,2,2]
# assuming jobs are sorted w.r.t profits
# I represented the jobs with string to be clear
jobs = ['a', 'b', 'c', 'd']
sjobs = sins.schedule(n, deadline, jobs)
print (sjobs)
if __name__ == "__main__":
main()

Related

N Puzzle with Depth First Search

I'm trying solve N Puzzle with Depth First Search using python 3.
With 3 x 3 puzzle it run good and fast but with 4 x 4 puzzle, it runs too slow and can't find solution with error: "MemoryError".
I also use "h(n) = depth + number of wrong tiles" to evaluate priority of each node.
I'm a newbie to python so hope you can help me with this
Here is my code:
import sys
import getopt
import random
import time
class State:
def __init__(self, parent, board, move, depth):
self.parent = parent
self.previousMove = move
self.board = board
self.map = ''.join(str(e) for e in board)
self.depth = depth
self.cost = self.calculateCost()
def calculateCost(self):
pos = 1
count = 0
for tile in self.board:
if tile == pos:
count += 1
pos += 1
return self.depth + 8 - count
class Puzzle:
def __init__(self, k, customBoard = None):
self.k = k
self.n = k*k - 1
self.sizeOfBoard = k*k
self.timeOfSolving = 0
self.timeOfGenerateSuccessors = 0
self.maxDeepSearch = 0
self.inititalState = State(None, self.createInitialBoard(customBoard), 'Start', 0)
self.goalBoard = self.createGoalBoard()
self.finalState = None
self.stateStorage = set() # Store states that have visited
self.path = [] # Store states that lead to goalstate
self.stack = []
def isSolvable(self, board):
# count invertion in puzzle's board
invCount = 0
for i in range(0, self.sizeOfBoard - 1):
if board[i] == 0:
continue
for j in range(i+1, self.sizeOfBoard):
if board[j] == 0:
continue
if board[i] > board[j]:
invCount += 1
# print(invCount)
if (invCount % 2 == 0):
return True
return False
def createInitialBoard(self, customBoard):
print("Creating initial state")
if customBoard is None:
board = []
lstAddSuccess = []
while 1:
board.clear()
lstAddSuccess.clear()
for count in range(0, self.k*self.k):
newTile = random.randint(0, self.n)
while newTile in lstAddSuccess:
newTile = random.randint(0, self.n)
lstAddSuccess += [newTile]
board += [newTile]
if self.isSolvable(board):
break
else:
board = [int(e) for e in customBoard]
if not self.isSolvable(board):
print("Cant find solution with this puzzle! Exiting...")
exit(-1)
return board
def createGoalBoard(self):
board = []
for count in range(1, self.n + 1):
board += [count]
board += [0]
return board
def printBoard(self, board):
for row in range(0, self.sizeOfBoard, self.k):
# for col in range(row, row + self.k):
print(board[row:row + self.k])
def generateSuccessors(self, currentState):
indexOfZero = currentState.board.index(0)
rowIndexOfZero = indexOfZero % self.k
colIndexOfZero = indexOfZero // self.k
lstSuccessors = []
# Slide to zero to up
if colIndexOfZero != 0:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero - self.k]
newState[indexOfZero - self.k] = 0
lstSuccessors.append(
State(currentState, newState, 'up', currentState.depth + 1))
# Slide zero to down
if colIndexOfZero != self.k - 1:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero + self.k]
newState[indexOfZero + self.k] = 0
lstSuccessors.append(
State(currentState, newState, 'down', currentState.depth + 1))
# slide zero to left
if rowIndexOfZero != 0:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero - 1]
newState[indexOfZero - 1] = 0
lstSuccessors.append(
State(currentState, newState, 'left', currentState.depth + 1))
# Slide zero to right
if rowIndexOfZero != self.k - 1:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero + 1]
newState[indexOfZero + 1] = 0
lstSuccessors.append(
State(currentState, newState, 'right', currentState.depth + 1))
lstSuccessorsCost = [ele.cost for ele in lstSuccessors]
lstSuccessorsInOrderOfCost = []
for i in range(0, len(lstSuccessorsCost)):
lstSuccessorsInOrderOfCost.append(lstSuccessors[lstSuccessorsCost.index(min(lstSuccessorsCost))])
lstSuccessorsCost[lstSuccessorsCost.index(min(lstSuccessorsCost))] = 100
return lstSuccessorsInOrderOfCost
def solvePuzzle(self, currentState):
self.stack.append(currentState)
self.stateStorage.add(currentState.map)
while len(self.stack) > 0:
currentState = self.stack.pop()
if currentState.board == self.goalBoard:
# find path
# self.printBoard(currentState.board)
self.finalState = currentState
print("Solving " + str(self.n) + " puzzle done!")
return
start_time_gen = time.time()
lstSuccessor = self.generateSuccessors(currentState)
end_time_gen = time.time()
timeOfGen = end_time_gen - start_time_gen
self.timeOfGenerateSuccessors += timeOfGen
for successor in lstSuccessor[::-1]:
if successor.map not in self.stateStorage:
self.stack.append(successor)
self.stateStorage.add(successor.map)
if successor.depth > self.maxDeepSearch:
self.maxDeepSearch += 1
print("Cant solve puzzle! Exiting...")
exit(-1)
def solve(self):
start_time = time.time()
self.solvePuzzle(self.inititalState)
end_time = time.time()
self.timeOfSolving = end_time - start_time
print("Running time: " + str(self.timeOfSolving))
print("Max Search Dept: " + str(self.maxDeepSearch))
print("Final State Dept: " + str(self.finalState.depth))
def printInitialBoard(self):
self.printBoard(self.inititalState.board)
def printPath(self):
if self.finalState is None:
print("No solution found!")
return
path = []
state = self.finalState
while (state is not None):
if state.previousMove is not None:
path.append(state.previousMove)
state = state.parent
print("path: "),
print(path[::-1])
def main(argv):
# if (len(argv) != 1 or int(argv[0]) not in range(1, 10000)):
# print("Input must be k of integer, which is k*k matrix of puzzle")
# exit()
# eight_puzzle = Puzzle(int(argv[0]))
k = int(input("Enter size of k * k puzzle, k = "))
while k not in range(2, 100):
print("k must be in range 2 - 100")
k = int(input("Enter size of k * k puzzle, k = "))
print("""
Choose:
1. Randome puzzle
2. Custome puzzle
""")
file = input()
if int(file) == 1:
puzzle = Puzzle(k)
elif int(file) == 2:
board = input("Enter puzzle: ")
puzzle = Puzzle(k ,list(board.split(" ")))
puzzle.printInitialBoard()
puzzle.solve()
puzzle.printPath()
if __name__ == "__main__":
main(sys.argv[1:])

knapsack branch and bound wrong result

I have converted the code given at this link into a python version. The code is supposed to calculate the correct value of maximum value to be filled in knapsack of weight W. I have attached the code below:
#http://www.geeksforgeeks.org/branch-and-bound-set-2-implementation-of-01-knapsack/
from queue import Queue
class Node:
def __init__(self):
self.level = None
self.profit = None
self.bound = None
self.weight = None
def __str__(self):
return "Level: %s Profit: %s Bound: %s Weight: %s" % (self.level, self.profit, self.bound, self.weight)
def bound(node, n, W, items):
if(node.weight >= W):
return 0
profit_bound = int(node.profit)
j = node.level + 1
totweight = int(node.weight)
while ((j < n) and (totweight + items[j].weight) <= W):
totweight += items[j].weight
profit_bound += items[j].value
j += 1
if(j < n):
profit_bound += (W - totweight) * items[j].value / float(items[j].weight)
return profit_bound
Q = Queue()
def KnapSackBranchNBound(weight, items, total_items):
items = sorted(items, key=lambda x: x.value/float(x.weight), reverse=True)
u = Node()
v = Node()
u.level = -1
u.profit = 0
u.weight = 0
Q.put(u)
maxProfit = 0;
while not Q.empty():
u = Q.get()
if u.level == -1:
v.level = 0
if u.level == total_items - 1:
continue
v.level = u.level + 1
v.weight = u.weight + items[v.level].weight
v.profit = u.profit + items[v.level].value
if (v.weight <= weight and v.profit > maxProfit):
maxProfit = v.profit;
v.bound = bound(v, total_items, weight, items)
if (v.bound > maxProfit):
Q.put(v)
v.weight = u.weight
v.profit = u.profit
v.bound = bound(v, total_items, weight, items)
if (v.bound > maxProfit):
# print items[v.level]
Q.put(v)
return maxProfit
if __name__ == "__main__":
from collections import namedtuple
Item = namedtuple("Item", ['index', 'value', 'weight'])
input_data = open("test.data").read()
lines = input_data.split('\n')
firstLine = lines[0].split()
item_count = int(firstLine[0])
capacity = int(firstLine[1])
print "running from main"
items = []
for i in range(1, item_count+1):
line = lines[i]
parts = line.split()
items.append(Item(i-1, int(parts[0]), float(parts[1])))
kbb = KnapSackBranchNBound(capacity, items, item_count)
print kbb
The program is supposed to calculate value of 235 for following items inside file test.data:
5 10
40 2
50 3.14
100 1.98
95 5
30 3
The first line shows number of items and knapsack weight. Lines below first line shows the value and weight of those items. Items are made using a namedtuple and sorted according to value/weight. For this problem I am getting 135 instead of 235. What am I doing wrong here?
EDIT:
I have solved the problem of finding correct items based on branch and bound. If needed, one can check it here
The problem is that you're inserting multiple references to the same Node() object into your queue. The fix is to initialize two new v objects in each iteration of the while-loop as follows:
while not Q.empty():
u = Q.get()
v = Node() # Added line
if u.level == -1:
v.level = 0
if u.level == total_items - 1:
continue
v.level = u.level + 1
v.weight = u.weight + items[v.level].weight
v.profit = u.profit + items[v.level].value
if (v.weight <= weight and v.profit > maxProfit):
maxProfit = v.profit;
v.bound = bound(v, total_items, weight, items)
if (v.bound > maxProfit):
Q.put(v)
v = Node() # Added line
v.level = u.level + 1 # Added line
v.weight = u.weight
v.profit = u.profit
v.bound = bound(v, total_items, weight, items)
if (v.bound > maxProfit):
# print(items[v.level])
Q.put(v)
Without these reinitializations, you're modifying the v object that you already inserted into the queue.
This is different from C++ where the Node objects are values that are implicitly copied into the queue to avoid aliasing problems such as these.

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

python script speed improvements

for my robot I am analyzing laser range data. I need to analyze a lot of samples per second. So speed is required.
I know python is not the right language based on this - but I don't want to switch for now as I am in the prototyping phase (will see if I ever get out of it :-) ).
At the moment I am stuck on squeezing more speed out of the analyzing code I have.
I pulled out the relevant code and created a small test. It would be brilliant if someone could give me a some hints on where to improve speed in this test script.
from math import degrees, radians, sin, cos, fabs
import time
class NewRobotMap(object):
def __init__(self, sizeX, sizeY, Resolution, RobotPosX, RobotPosY, RobotTheta, ServoPos, mapMaxOcc, mapMaxFree, OccValue, EmptyValue):
self.sizeX = sizeX
self.sizeY = sizeY
self.RobotPosX = int(RobotPosX)
self.RobotPosY = int(RobotPosY)
self.mapResolution = int(Resolution)
self.StartPosX = int(RobotPosX)
self.StartPosY = int(RobotPosY)
self.RobotTheta = float(RobotTheta)
self.EmptyValue = EmptyValue
self.ServoPos = ServoPos
self.mapMaxOcc = mapMaxOcc
self.mapMaxFree = mapMaxFree
self.mapOccValue = OccValue
self.RobotPosOldX = ""
self.RobotPosOldY = ""
def clear(self):
self.RobotMap = [[self.EmptyValue for i in xrange(self.sizeY)] for j in xrange(self.sizeX)]
def updateMap(self ,x ,y , Val):
oldval = self.RobotMap[x][y]
self.RobotMap[x][y]=self.RobotMap[x][y] + Val
if self.RobotMap[x][y] > self.mapMaxOcc:
self.RobotMap[x][y] = self.mapMaxOcc
elif self.RobotMap[x][y] < self.mapMaxFree:
self.RobotMap[x][y] = self.mapMaxFree
return oldval, self.RobotMap[x][y]
def setOcc(self,x,y):
self.RobotMap[x][y] = self.mapMaxOcc
def updateRobot(self,theta,x,y):
robotThetaold=self.RobotTheta
self.RobotTheta = float(theta)
self.RobotPosX = int(round(self.StartPosX + float(int(x)/self.mapResolution), 0))
self.RobotPosY = int(round(self.StartPosY - float(int(y)/self.mapResolution),0))
if x != self.RobotPosOldX or y != self.RobotPosOldX:
self.RobotPosOldX = x
self.RobotPosOldY = y
return True
else:
self.RobotPosOldX = x
self.RobotPosOldY = y
return False
def getRobotPos(self):
return self.RobotPosX, self.RobotPosY
def display(self):
s = [[str(e) for e in row] for row in self.RobotMap]
lens = [len(max(col, key=len)) for col in zip(*s)]
fmt = '\t'.join('{{:{}}}'.format(x) for x in lens)
table = [fmt.format(*row) for row in s]
print '\n'.join(table)
def updateServoPos(self, newServoPos):
self.ServoPos = newServoPos
templateData = {
'MapWidth' : 800,
'MapHeight': 600,
'StartPosX' : 500,
'StartPosY' : 300,
'StartTheta' : 0,
'Resolution' : 5,
'mapThresholdFree' : 126,
'mapThresholdOcc' : 130, #169
'EmptyValue' : 128,
'mapMaxOcc' : 137,
'mapMaxFree' : 119,
'ServoPos' : 0,
'CurrentPosX' : 0,
'CurrentPosY' : 0,
'CurrentTheta' : 0,
'SafeZone' : 10
}
templateData["MapHeight"] = templateData["MapHeight"] / templateData["Resolution"]
templateData["MapWidth"] = templateData["MapWidth"] / templateData["Resolution"]
templateData["StartPosX"] = templateData["StartPosX"] / templateData["Resolution"]
templateData["StartPosY"] = templateData["StartPosY"] / templateData["Resolution"]
def updateSonarCalcMapVal(val):
mapThresholdFree = templateData["mapThresholdFree"]
mapThresholdOcc = templateData["mapThresholdOcc"]
#oldval
if val[0] <= mapThresholdFree:
oldval = 0
elif mapThresholdFree < val[0] < mapThresholdOcc:
oldval = 1
elif val[0] >= mapThresholdOcc:
oldval = 2
# newval
if val[1] <= mapThresholdFree:
newval = 0
elif mapThresholdFree < val[1] < mapThresholdOcc:
newval = 1
elif val[1] >= mapThresholdOcc:
newval = 2
if oldval != newval:
return newval
else:
return 'n'
def dur( op=None, clock=[time.time()] ):
if op != None:
duration = time.time() - clock[0]
print '%s finished. Duration %.6f seconds.' % (op, duration)
clock[0] = time.time()
def updateIRWrite(RobotPos, coord, updateval):
XtoUpdate=RobotPos[0] + coord[0]
YtoUpdate=RobotPos[1] - coord[1]
val = map.updateMap(XtoUpdate, YtoUpdate , updateval)
newval=updateSonarCalcMapVal(val)
########### main Script #############
map=NewRobotMap(templateData["MapWidth"],templateData["MapHeight"], templateData["Resolution"], templateData["StartPosX"],templateData["StartPosY"], templateData["StartTheta"], templateData["ServoPos"],templateData["mapMaxOcc"],templateData["mapMaxFree"],templateData["mapThresholdOcc"],templateData["EmptyValue"])
map.clear()
dur()
for x in xrange(0,10001*40):
updateIRWrite((100,100), (10,10), 1)
dur("loops")
I tried a numpy array as self.RobotMap in the NewRobotMap class/object. But this was much slower.
Few tips
Minimize too deep redirections
Your code here:
def updateMap(self ,x ,y , Val):
oldval = self.RobotMap[x][y]
self.RobotMap[x][y]=self.RobotMap[x][y] + Val
if self.RobotMap[x][y] > self.mapMaxOcc:
self.RobotMap[x][y] = self.mapMaxOcc
elif self.RobotMap[x][y] < self.mapMaxFree:
self.RobotMap[x][y] = self.mapMaxFree
return oldval, self.RobotMap[x][y]
is all the time repeating self.RobotMap[x][y] what requires 4 levels of hops to get the value (self -> RobotMap -> [x] -> [y])
This can be optimized:
In place update
old:
self.RobotMap[x][y]=self.RobotMap[x][y] + Val
new (saving diving for existing value second time)
self.RobotMap[x][y] += Val
Use local variable instead of deeply nested structure
def updateMap(self ,x ,y , Val):
oldval = self.RobotMap[x][y]
newval = oldval + Val
if newval > self.mapMaxOcc:
newval = self.mapMaxOcc
elif newval < self.mapMaxFree:
newval = self.mapMaxFree
return oldval, newval
Note, that your old return oldval, self.RobotMap[x][y] is not only returning a value, but you have already modified the self.RobotMap[x][y] anyway (as it is mutable), so if you rely on that, you could be surprised.
Using global variables instead of tempateData dictionary
Changing dictionary into global variable speeded up the run a bit as it removed one level ov indirection. I know, it looks nasty, but this may happen with optimization.
Skip returning self.RobotMap[x][y]
Consider saving returning self.RobotMap[x][y] if this not necessary, or if you have already changed that value.
Quick clear
change original:
def clear(self):
self.RobotMap = [[self.EmptyValue for i in xrange(self.sizeY)] for j in xrange(self.sizeX)]
to:
def clear(self):
self.RobotMap = self.sizeY * [self.sizeY * [self.EmptyValue]]
My test show about twice as fast execution for x = 3, y = 5, larger sizez could be even better.
Modified code - from 0.790581 to 0.479875 seconds
from math import degrees, radians, sin, cos, fabs
import time
templ_MapWidth = 800
templ_MapHeight = 600
templ_StartPosX = 500
templ_StartPosY = 300
templ_StartTheta = 0
templ_Resolution = 5
templ_mapThresholdFree = 126
templ_mapThresholdOcc = 130
templ_EmptyValue = 128
templ_mapMaxOcc = 137
templ_mapMaxFree = 119
templ_ServoPos = 0
templ_CurrentPosX = 0
templ_CurrentPosY = 0
templ_CurrentTheta = 0
templ_SafeZone = 10
templ_MapHeight = templ_MapHeight / templ_Resolution
templ_MapWidth = templ_MapWidth / templ_Resolution
templ_StartPosX = templ_StartPosX / templ_Resolution
templ_StartPosY = templ_StartPosY / templ_Resolution
class NewRobotMap(object):
def __init__(self, sizeX, sizeY, Resolution, RobotPosX, RobotPosY, RobotTheta, ServoPos, mapMaxOcc, mapMaxFree, OccValue, EmptyValue):
self.sizeX = sizeX
self.sizeY = sizeY
self.RobotPosX = int(RobotPosX)
self.RobotPosY = int(RobotPosY)
self.mapResolution = int(Resolution)
self.StartPosX = int(RobotPosX)
self.StartPosY = int(RobotPosY)
self.RobotTheta = float(RobotTheta)
self.EmptyValue = EmptyValue
self.ServoPos = ServoPos
self.mapMaxOcc = mapMaxOcc
self.mapMaxFree = mapMaxFree
self.mapOccValue = OccValue
self.RobotPosOldX = ""
self.RobotPosOldY = ""
def clear(self):
self.RobotMap = self.sizeX * [self.sizeY * [self.EmptyValue]]
def updateMap(self, x, y, Val):
oldval = self.RobotMap[x][y]
newval = oldval + Val
if newval < self.mapMaxFree:
return oldval, self.mapMaxFree
if newval > self.mapMaxOcc:
return oldval, self.mapMaxOcc
return oldval, newval
def setOcc(self, x, y):
self.RobotMap[x][y] = self.mapMaxOcc
def updateRobot(self, theta, x, y):
robotThetaold = self.RobotTheta
self.RobotTheta = float(theta)
self.RobotPosX = int(round(self.StartPosX + float(int(x)/self.mapResolution), 0))
self.RobotPosY = int(round(self.StartPosY - float(int(y)/self.mapResolution), 0))
if x != self.RobotPosOldX or y != self.RobotPosOldX:
self.RobotPosOldX = x
self.RobotPosOldY = y
return True
else:
self.RobotPosOldX = x
self.RobotPosOldY = y
return False
def getRobotPos(self):
return self.RobotPosX, self.RobotPosY
def display(self):
s = [[str(e) for e in row] for row in self.RobotMap]
lens = [len(max(col, key=len)) for col in zip(*s)]
fmt = '\t'.join('{{:{}}}'.format(x) for x in lens)
table = [fmt.format(*row) for row in s]
print '\n'.join(table)
def updateServoPos(self, newServoPos):
self.ServoPos = newServoPos
def updateSonarCalcMapVal(org, new):
mapThresholdFree = templ_mapThresholdFree
mapThresholdOcc = templ_mapThresholdOcc
#oldval
if org <= mapThresholdFree:
oldval = 0
elif mapThresholdFree < org < mapThresholdOcc:
oldval = 1
elif org >= mapThresholdOcc:
oldval = 2
# newval
if new <= mapThresholdFree:
newval = 0
elif mapThresholdFree < new < mapThresholdOcc:
newval = 1
elif new >= mapThresholdOcc:
newval = 2
if oldval != newval:
return newval
else:
return 'n'
def dur(op=None, clock=[time.time()]):
if op != None:
duration = time.time() - clock[0]
print '%s finished. Duration %.6f seconds.' % (op, duration)
clock[0] = time.time()
def updateIRWrite(RobotPos, coord, updateval):
XtoUpdate = RobotPos[0] + coord[0]
YtoUpdate = RobotPos[1] - coord[1]
newval = updateSonarCalcMapVal(*mymap.updateMap(XtoUpdate, YtoUpdate, updateval))
########### main Script #############
mymap = NewRobotMap(templ_MapWidth, templ_MapHeight, templ_Resolution, templ_StartPosX, templ_StartPosY, templ_StartTheta, templ_ServoPos, templ_mapMaxOcc, templ_mapMaxFree, templ_mapThresholdOcc, templ_EmptyValue)
mymap.clear()
dur()
for x in xrange(0, 10001*40):
updateIRWrite((100, 100), (10, 10), 1)
dur("loops")
Conclusions
The code definitely needs review for doing correct work. E.g. there are methods, which are not used at all and other calls, which never use returned value.
But some optimization could be shown. Generally, following is good to follow:
Make your code running correctly first
Clarify what is acceptable speed, do not optimize, if not necessary
Measure, profile
Start optimizing in busiest loops, there are best chances to speed things up. In them, each line of code counts.
Can you install PyPy and run your script with it instead of CPython (the default) ? It should work as a drop-in replacement of CPython.
http://pypy.org/
It is based on (tracing?) JIT and famous for its high runtime performance.
http://speed.pypy.org/

Python minimax for tictactoe

After completely failing the minimax implementation for tic tac toe, I fail to see what's wrong. Right now, my AI just goes around in a circle...
import collections
class InvalidLocationError(Exception): pass
import copy
class Board(object):
def __init__(self, board=None):
if board is None:
self.clear()
else:
self._board = board[:]
def place(self, i, row, column):
if not ((0 <= row <= 2) and (0 <= column <= 2)):
raise InvalidLocationError("Invalid Location.")
if self._board[row][column]:
raise InvalidLocationError("There's already a piece there")
self._board[row][column] = i
return self.checkVictory()
def check(self, row, column):
return self._board[row][column]
def checkVictory(self, board=None):
if board is None:
board = self._board
draw = True
for i in xrange(3):
r = self.rowcount(i)
c = self.colcount(i)
if i < 3:
d = self.diagcount(i)
else:
d = {0: 0, 1: 0, 2: 0}
for j in xrange(1, 3):
if d[j] == 3 or r[j] == 3 or c[j] == 3:
return j
if r[0] > 0 or c[0] > 0:
draw = False
if draw:
return -1
return 0
def rowcount(self, row):
return collections.Counter(self._board[row])
def colcount(self, col):
return collections.Counter([self._board[i][col] for i in xrange(3)])
def diagcount(self, left=True):
if left:
a = [self._board[0][0], self._board[1][1], self._board[2][2]]
else:
a = [self._board[0][2], self._board[1][1], self._board[2][0]]
return collections.Counter(a)
def clear(self):
self._board = ([0, 0, 0], [0, 0, 0], [0, 0, 0])
def __str__(self):
return "\n".join(map(lambda x: " ".join(map(lambda y : str(y), x)), self._board))
#staticmethod
def flipPiece(p):
return int(not (p - 1)) + 1
class AI(object):
class Node(object):
def __init__(self, board, nextMove):
self.board = board
self.nextMove = nextMove
self.paths = []
self.score = None
template = self.board._board[:]
for r, row in enumerate(template):
for c, val in enumerate(row):
if val == 0:
template[r][c] = nextMove
self.paths.append(copy.deepcopy(template))
template[r][c] = 0
def __init__(self, mypiece, depth=8):
self.mypiece = mypiece
self.enemypiece = Board.flipPiece(mypiece)
self.depth = depth
def decide(self, board):
startNode = self.Node(board, self.mypiece)
best = self.minimax(startNode, self.depth)
for node in startNode.paths:
if node.value == best:
break
found = False
for row in xrange(3):
for col in xrange(3):
if board.check(row, col) != node.board.check(row, col):
found = True
break
if found:
break
print row, col
return row, col
def minimax(self, node, depth):
victory = node.board.checkVictory()
if victory:
if victory == self.mypiece:
h = 1
elif victory == -1:
h = 0
else:
h = -1
node.value = h
return h
if depth <= 0:
# h = self.heuristic(node.board, node.nextMove) # This is to the heuristic, which uses nextMove to evalate.
node.value = 0
return 0
h = -1
flip = Board.flipPiece(node.nextMove)
for i, board in enumerate(node.paths):
node.paths[i] = self.Node(Board(board), flip) # This is to the Node, which takes the nextMove of itself (which translates to the next next move from the current node)
score = self.minimax(node.paths[i], depth-1)
h = max(h, score) if node.nextMove == self.mypiece else min(h, score)
node.value = h
return h
Why is this happening?

Categories