I'm programming Clarke and Wright's savings algorithm to design vehicle routes from a depot to a set of customers. Right now, the code gets stuck in the final if statement if none of the conditions is met. What I want is that if ALL the cust_pairs have been checked and there is NO unserved cust_pair left which is either at the start or end of the previous route The code should break out of the second for loop. And then, go back to the first for loop to find a customer pair for starting a new route.
I've tried some things with 'break' and 'continue' but can not get it working.
def inPrevious(new,existing):
start = existing[0]
end = existing[len(existing)-1]
if new == start:
return 1
elif new == end:
return 0
else:
return -1
idx = -1
while not(allCustomersServed):
for c in cust_pairs:
# find initial cust_pair with high savings
idx += 1
routes[idx] = ([c[0],c[1]])
break
#finding a cust that is either at the start or end of previous route
for c in cust_pairs:
# find feasible cust_pair that is either at the start or end of previous route
res = inPrevious(c[0], routes[idx])
if res == 0:
# append c[1] to route
elif res == 1:
# insert c[1] at position 0 in route
elif res == -1:
res = inPrevious(c[1], routes[idx])
if res == 0:
# append c[0] to route
elif res == 1:
# insert c[0] at position 0 in route
Related
Summary
When groupby is used, the result is as follows.
The value of 2.19 is the user-defined function's return value of the first group. That is, when the function is implemented for mulCut[(mulCut['date'] == '2018-03-05') & (mulCut['moneyness'] == 'atm')], I get 2.19.
Explanation
I'm trying to get different returns by different groups by using .groupby.apply(). In my case, groups are split by two variables 'date' and 'moneyness' as below. As you can see DataFrame below, 'date' contains four categorical groups 'atm', 'itm', 'otm' and 'tot'.
And my user-defined function is as follows. The function calculates the return from trading kospi index between 9:05 and 14:50. Briefly, trading strategy is buying or selling kospi index according to signal. '>= sensitivity' is buy signal and '<= 1/sensitivity' is sell signal. Since I assume that I can sell or buy all my budget for each signal, when short selling occurred already, sell signal is ignored. Similary, if I bought kospi index already, buy signal is ignored. Lastly, at last minute (14:50), trade must be liquidated. That is, if my status is short selling in 14:49, I must buy kospi200 no matter what signal I receive in 14:50. Similarly, if my status is buying in 14:49, I must sell kospi200.
def get_onedayRt(onedayDf, timeVrbl, cpVrbl, kospiVrbl, sensitivity):
onedayDf['action'] = np.nan
state = 0 # 0: can buy or short sell, 1: can only sell, -1: can only buy
value = 0 # return of simulation
targetDf = onedayDf.sort_values(timeVrbl)
targetDf = targetDf.reset_index(drop = True)
lastidx = len(onedayDf) - 1
for idx, timeData in targetDf.iterrows():
if timeData[cpVrbl] >= sensitivity:
if state == -1:
state += 1
targetDf.loc[idx, 'action'] = 1 #buy
value -= timeData[kospiVrbl]
elif state == 0:
state += 1
targetDf.loc[idx, 'action'] = 1
value -= timeData[kospiVrbl]
elif timeData[cpVrbl] <= 1/sensitivity:
if state == 1:
state -= 1
targetDf.loc[idx, 'action'] = -1 # sell
value += timeData[kospiVrbl]
elif state == 0:
state -= 1
targetDf.loc[idx, 'action'] = -1
value += timeData[kospiVrbl]
if lastidx - 1 == idx:
break # last action needs to be determied as below
if state == -1:
targetDf.loc[lastidx, 'action'] = 1
value -= targetDf.loc[lastidx, kospiVrbl]
elif state == 1:
targetDf.loc[lastidx, 'action'] = -1
value += targetDf.loc[lastidx, kospiVrbl]
return value
I found that my function works appropriately for each specific group. That is, the code below works. I could get 2.97 which I wanted to get.
tmp = mulCut[(mulCut['date'] == '2018-03-05') & (mulCut['moneyness'] == 'tot')]
get_onedayRt(tmp, 'time', 'call/put', 'kospi200', 1)
Therefore, I wonder why my user define function returns only first group's return when executing groupby.apply? And how can I edit my code to fix the problem?
Thank you for reading my long question.
I solved my problem finally...
the first line of my function was the source of my problem. After the line is deleted, my code works properly.
I am working with this problem (https://open.kattis.com/problems/whowantstoliveforever). As the problem states, my program has to determine if the universe lives or dies based on the input 0s and 1s.
to determine the next value of the i-th bit, look at the current value of the bits at positions i−1 and i+1 (if they exist; otherwise assume them to be 0). If you see exactly one 1, then the next value of the i-th bit is 1, otherwise it is 0. All the bits change at once, so the new values in the next state depend only on the values in the previous state. We consider the universe dead if it contains only zeros.
My current solution works on the example input file, however it fails when submitting it to Kattis. (Wrong Answer)
Below is my code.
import sys
def get_bit(bits, i):
if 0 <= i < len(bits):
return int(bits[i])
else:
return 0
def get_new_state(old_state):
new_state = []
for index in range(len(old_state)):
if (get_bit(old_state, index-1) == 0 and get_bit(old_state, index+1) == 0) or (get_bit(old_state, index-1) == 1 and get_bit(old_state, index+1) == 1):
new_state.append(0)
elif(get_bit(old_state, index-1) == 0 and get_bit(old_state, index+1) == 1) or (get_bit(old_state, index-1) == 1 and get_bit(old_state, index+1) == 0):
new_state.append(1)
return new_state
def is_dead(state):
if len(set(state)) == 1:
return True
else:
return False
def foresee_fate(state):
seen = []
while True:
if is_dead(state):
return False
if state in seen:
return True
seen.append(state)
state = get_new_state(state)
def print_result(boolean):
print("LIVES" if boolean else "DIES")
num_cases = int(sys.stdin.readline().strip())
for i in range(num_cases):
cur_state = []
case = sys.stdin.readline().strip()
for char in case:
cur_state.append(char)
print_result(foresee_fate(cur_state))
Please let me know what I can do to improve this program.
As suggested, I have added the following to my code and IT works now. However, I ran into a new problem. now I'm getting "Time Limit Exceeded" > 3.00 s.
def is_dead(state):
if set(state).pop() == 1:
return False
elif len(set(state)) == 1:
return True
else:
return False
Please let me know if there is any suggestion on getting around this problem
I'm not really new to python but I came across this problem that has just puzzled me.
So I was solving the maze runner problem, using A* and then was finding the hardest possible maze for a given dimension. For this purpose, I created a function called generateHardMaze() that is called from the main function and takes an attribute newMaze.
Now here is where things get weird, when I change the value of newMaze in the if condition within the while loop the hardMaze value changes without the code entering the second if condition. I'm not really sure why this happening was hoping someone could help me.
I'm using pycharm as my IDE and python3.6.* if that makes any difference.
I'm sure this isn't how oops works but I'm thinking this is a python thing. Has anyone ever come across anything like this? If yes please sympathize.
Thanks in advance.
def solveMazeAManH(newMaze,rows,cols):
startTime = time.time()
backTrackPriority = []
setup_cells(rows, cols)
# start and end points of the maze
start = (0, 0)
end = (rows - 1, cols - 1)
current = start
print("The path to be take is: ")
print(current)
frinLength = 0
# traversing the neighbours
while current != end:
unvisited.remove(current)
neighboursDFSandA(newMaze, current, rows, cols)
heuristic = calManhattanDis(current, end) # finding the heuristic for every traversal
try:
if not currentNeighbours:
if not backTrackPriority:
print("No path available!")
return 0
else:
while not currentNeighbours:
current = nextPopMan(backTrackPriority, end)
backTrackPriority.remove(current)
neighboursDFSandA(newMaze, current, rows, cols)
neighbor = leastPathChildMan(heuristic, current, end)
backTrackPriority.append(current)
current = neighbor
print(current)
frinLength += 1
except:
print("No path Found!")
return 0
return frinLength
endTime = time.time()
print("The time taken to solve the maze using A* with manhattan distance: ")
print(startTime - endTime)
def generateHardMaze(newMazes):
rows = len(newMazes)
cols = len(newMazes[0])
hardMaze = newMaze
print("Solving the original maze!")
fringLength = solveMazeAManH(newMazes, rows, cols)
print("Creating new harder Maze:")
pFlag = True
pCout = 0
while pFlag:
count = 0
flag = True
while flag:
point = choice(setup_cells(rows, cols))
if (newMazes[point[0]][point[1]] == 1):
newMazes[point[0]][point[1]] = 0
else:
newMazes[point[0]][point[1]] = 1
if (fringLength < solveMazeAManH(newMazes, rows, cols)):
print("Harder Maze--------------------")
hardMaze = newMaze
fringLength = solveMazeAManH(newMazes, rows, cols)
count = 0
else:
count += 1
if count >= 10:
flag = False
print("one")
newMazes = creatMaze(rows)
pCout += 1
if pCout >= 100:
pFlag = False
print(hardMaze)
I am trying to write code that is an insertion sort. I am trying to get the code to take 2 values and put them into a new list while sorting it. So far it just puts the values into the list without them being sorted, i'm not quite sure why
pos = 0
pos2 = 1
go = True
while go == True:
for i in range(len(ex)-1):
stack.append(ex[pos])
print(stack)
stack.append(ex[pos2])
print(stack)
if stack[pos] > stack[pos2]:
stack[pos], stack[pos2] = stack[pos2], stack[pos]
print(stack)
pos = pos + 2
pos2 = pos2 + 2
I know it's not efficient, but it is based off code i made for a bubble sort which does
go = True
add = 0
while go == True:
for i in range(len(ex)-1):
if ex[i] > ex[i+1]:
go = True
ex[i], ex[i+1] = ex[i+1], ex[i] #flips the numbers in the list
print(ex)
add = add + 1
if add >= len(ex):
go = False
EDIT
I have changed it drastically, but there is still a problem. It only swaps the values once, even if it needs to be swapped multiple times to be in the right place. Here is the code
pos = 0
while pos < len(ex)-1:
for i in range(len(ex)-1):
stack.append(ex[i])
print(stack)
if stack[i-1] > stack[i]:
stack[i-1], stack[i] = stack[i], stack[i-1]
pos = pos + 1
else:
pos = pos + 1
You have to compare ex[pos] with ex[pos2] then you append the right element first :
if ex[pos] > ex[pos2]:
stack[pos].append(ex[pos2])
else stack[pos].append(ex[pos])
print(stack)
Here is the pseudo code for a classic insertion sort from https://visualgo.net/sorting a great resource for learning sorting algorithms:
mark first element as sorted
for each unsorted element
'extract' the element
for i = lastSortedIndex to 0
if currentSortedElement > extractedElement
move sorted element to the right by 1
else: insert extracted element
And here is how you could implement insertion sort in python:
def insertion_sort(l):
for i in range(1, len(l)):
j = i-1
key = l[i]
while (l[j] > key) and (j >= 0):
l[j+1] = l[j]
j -= 1
l[j+1] = key
return l
Once you understand the basic insertion sort you should be able to understand where you went wrong in your implementation in that you are not properly storing stack[pos] in your implementation.
I am implementing a Python version of the game Othello / Reversi. However, my algorithm seems to be having trouble when searching in the southwest direction.
Here are some important functions to understand how my current code works:
def _new_game_board(self)->[[str]]:
board = []
for row in range(self.rows):
board.append([])
for col in range(self.columns):
board[-1].append(0)
return board
def _is_valid_position(self, turn:list)->bool:
'''return true if the turn is a valid row and column'''
row = int(turn[0]) - 1
column = int(turn[1]) - 1
if row >= 0:
if row < self.rows:
if column >= 0:
if column < self.columns:
return True
else:
return False
def _is_on_board(self, row:int, col:int)->bool:
'''returns true is coordinate is on the board'''
if row >=0:
if row < self.rows:
if col >=0:
if col < self.columns:
return True
def _searchNorthEast(self)->None:
'''Search the board NorthEast'''
print("NorthEast")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row += 1
column -= 1
if self._is_on_board(row, column):
print("column searching NorthEast on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row += 1
column -= 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _searchSouthWest(self)->None:
'''Search the board SouthWest'''
print("in SouthWest")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row -= 1
column += 1
if self._is_on_board(row, column):
print("column searching SouthWest on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row -= 1
column += 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _move_is_valid(self, turn:list)->bool:
'''Verify move is valid'''
self._to_be_flipped = list()
self._opponent = self._get_opposite(self.turn)
if self._is_valid_position(turn):
self.move_row = int(turn[0]) - 1
self.move_column = int(turn[1]) - 1
self._searchRight()
self._searchLeft()
self._searchUp()
self._searchDown()
self._searchNorthWest()
self._searchNorthEast
self._searchSouthEast()
self._searchSouthWest()
if len(self._to_be_flipped) > 0:
return True
else:
return False
Now let's say the current board looks like the following:
. . . .
W W W .
. B B .
. B . .
Turn: B
and the player makes a move to row 1 column 4, it says invalid because it does not detect the white piece in row 2 column 3 to be flipped. All my other functions are written the same way. I can get it to work in every other direction except in this case.
Any ideas why it is not detecting the piece in this diagonal direction?
Don't Repeat Yourself. The _search* methods are extremely redundant which makes it difficult to see that the signs in
row -= 1
column += 1
are correct. Since you've given only two directions (NE, SW) and no documentation of the board orientation, I cannot tell if the signs agree with the board layout or even agree with themselves.
The _search* methods are also too long and should be divided into multiple functions, but that's a secondary concern.
I agree with msw about not repeating stuff. It is tempting to go ahead and do what you can once you see it, but generalizing will save you the headaches of debugging.
Here is some pseudocode that should give the general idea. I might not be able to finagle working with your code, but hopefully this shows how to reduce repetitive code. Note it doesn't matter if -1 is up or down. The board class is simply a 2x2 array of (open square/player 1's piece/player 2's piece,) along with whose turn it is to move.
# x_delta and y_delta are -1/0/1 each based on which of the up to 8 adjacent squares you are checking. Player_num is the player number.
def search_valid(x_candidate, y_candidate, x_delta, y_delta, board, player_num):
y_near = y_candidate + y_delta
x_near = x_candidate + x_delta
if x_near < 0 or x_near >= board_width:
return False
if y_near < 0 or y_near >= board_width:
return False # let's make sure we don't go off the board and throw an exception
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == 0:
return False #empty square
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num:
return False #same color piece
return True #if you wanted to detect how many flips, you could use a while loop
Now a succinct function can loop this search_valid to see whether a move is legal or not e.g.
def check_valid_move(x_candidate, y_candidate, board, player_num):
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if not x and not y:
continue # this is not a move. Maybe we don't strictly need this, since board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num anyway, but it seems like good form.
if search_valid(x_candidate, y_candidate, dx, dy, board, player_num):
return True
return False
A similar function could actually flip all the opposing pieces, but that's a bit trickier. You'd need a while function inside the for loops. But you would not have to rewrite code for each direction.