Merge Sort returns the same array in Python - python-2.7

for merge sort i wrote this code:
I have tested merge function that works correctly. but in mergeSort function i coudn't handle the arrays. it returns the same list as the input list.
def mergeSort(a):
l, h = 0, len(a)-1
mid = (l+h)/2
if (l<h-1): #the lowest length must be 2
mergeSort(a[l:mid+1])
mergeSort(a[mid+1:h+1])
return merge(a[l:mid+1],a[mid+1:h+1])
def merge(a,b):
n_a = len(a)
n_b = len(b)
c = [[] for i in range(n_a + n_b)]
i,j,k=0,0,0
while (i<n_a and j<n_b):
if a[i]<b[j]:
c[k] = a[i]
i += 1
else:
c[k]= b[j]
j += 1
k += 1
while(i<n_a):
c[k] = a[i]
k+=1
i+=1
while(j< n_b):
c[k] = b[j]
k+=1
j+=1
return c

I would rewrite merge as so:
def mergeSort(a):
h = len(a)
mid = h / 2
if h >= 2:
return merge(mergeSort(a[:mid]), mergeSort(a[mid:]))
else:
return a
A few notes:
l is always 0, might as well remove it
h is len(a) - 1, but then you use h + 1, might as well use h = len(a)
Actually writting h >= 2 makes it clearer that you need at least 2 items in your list
mid can be len(a) / 2.
when taking the complete beginning/end of an array in a slice, the first/last bound is not required

Related

How to get all solutions for an integer program in ortools?

I am trying to get all solutions for a Mixed Integer program through ortools. I have two lists x and y of size 4. I want to get all solutions which satisfy sum(x) = 4 * sum(y). I created a function which takes list of past solutions as input and returns next solution. I am able to get only 2 solutions even though there are more. What am I doing wrong here?
I am expecting the following solutions
Solution 1:
xs1 = [0,0,0,0], ys1 = [0,0,0,0]
Solution 2:
xs2 = [4,0,0,0], ys2 = [1,0,0,0]
Solution 3:
xs3 = [0,4,0,0], ys3 = [1,0,0,0]
Solution 4:
xs4 = [0,0,4,0], ys4 = [0,0,1,0]
and soon on
from ortools.linear_solver import pywraplp
def opt(xs, ys):
solver = pywraplp.Solver.CreateSolver('SCIP')
infinity = solver.infinity()
# x and y are integer non-negative variables.
n = 4
M = 20
x = [0]* n
y = [0]* n
w = [[0]* n]*len(xs)
δ = [[0]* n]*len(xs)
for i in range(0,n):
x[i] = solver.IntVar(0, 20, 'x'+str(i))
y[i] = solver.IntVar(0, 20, 'y'+str(i))
for j in range(len(xs)):
w[j][i] = solver.IntVar(0, 20, 'zp'+str(j)+ '-' + str(i))
δ[j][i] = solver.IntVar(0, 1, 'δ'+str(j)+ '-' + str(i))
for j in (range(len(xs))):
for i in range(0,n):
solver.Add((w[j][i] - x[i] + xs[j][i]) >=0)
solver.Add((w[j][i] - x[i] + xs[j][i]) <= M*(1-δ[j][i]))
solver.Add((w[j][i] + x[i] - xs[j][i]) >=0)
solver.Add((w[j][i] + x[i] - xs[j][i]) <= M*δ[j][i])
for j in range(len(xs)):
solver.Add(solver.Sum([w[j][i] for i in range(0,n)]) >= 1)
solver.Add(solver.Sum([x[i] for i in range(0, n)]) - 4 * solver.Sum([y[i] for i in range(0, n)]) == 0)
solver.Minimize(solver.Sum([x[i] for i in range(0, n)]))
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
solver_x = [0]*n
solver_y = [0]*n
for i in range(0,n):
solver_x[i] = x[i].solution_value()
solver_y[i] = y[i].solution_value()
return ([solver_x, solver_y, solver.Objective().Value()])
else:
print('No Solution')
return ([[0], [0]], -1)
psx = [[0,0,0,0], [0,4,0,0]]
psy = [[0,0,0,0], [1,0,0,0]]
ns = opt(psx, psy)
print(ns)
Output:
No Solution
([[0], [0]], -1)
Reference:
Finding multiple solutions to general integer linear programs
How to write constraints for sum of absolutes
If you have a pure integer programming model, you can use the CP-SAT solver which allows you to print all the solutions [See this].

'function' object has no attribute '__getitem__'

This is my first time coding. I'm doing it as ab elective module. I have to program an ai_player to go from playing randomly to winning and I'm stuck. Any advice would be appreciated. The game is Connect 4. i keep getting "object has no attribute" error.
import random
import time
def board():
for i in range(0, 8, 1):
for j in range(0, 10, 1):
board[i][j] = 0
return board
def move(board, valid_move):
start_time = time.time()
x = 0
while x == 0:
i = range(7, -1, -1)
j = range(0, 10, 1)
first_move = board[i][j]
board[7][4] = 1
if board[i-1][j] == 0: #above
first_move = [i, j]
x = 1
print " valid above"
return j
elif (board[i][j+1] == 0 and (i <= 7 and j <= 9)) or (board[i-1][j+1] == 0 and (i <= 7 and j <= 9)) or (board[i-1][j+1] == 0 and (i <= 7 and j <= 9)): #right
first_move = [i, (j+1)]
x = 1
print " valid right"
return (j+1)
elif board[i][j-1] == 0 or board[i-1][j-1] == 0 or board[i-1][j-1] == 0: #left
first_move = [i, (j-1)]
x = 1
print " valid left"
return (j-1)
else:
r = random.randint(0, 7)
c = random.randint(0, 9)
first_move = [r, c]
x = 1
print " random move"
return c
end_time = time.time() - start_time
print end_time
return first_move
File "F:/5. Fifth year/1st Semester/MPR 213 2016/Project 2016/attempts.py", line 20, in board
board[i][j] = 0
TypeError: 'function' object has no attribute '__getitem__'
It looks like you're trying to create a multidimensional list called board. This is not how you do that though, what you've actually done is created a function called board, and then you try to index that function, which fails since it's not a list.
To create board, use something like
board = [[0] * 10 for i in range(0, 8)]

Out of range error - merge sort algorithm

I am trying to implement the merge sort algorithm using the following code but am getting a list index is out of range error.
def mergeSort (unSortedList):
if len(unSortedList) == 1 :
return unSortedList
else:
midpoint = len(unSortedList)//2
A = mergeSort (unSortedList[:midpoint] )
B = mergeSort (unSortedList[midpoint:] )
i = 0
j = 0
C = []
for k in range(len(unSortedList)):
if A[i] >= B[j]:
C.append(A[i])
if i == len(A):
C.append(B[j:])
else:
i += 1
elif A[i] < B[j] :
C.append(B[j])
if j == len(B):
C.append(A[i:])
else:
j += 1
return C
testlist = [2,1,4,2,5,6,8,9]
print (mergeSort(testlist))
Any help would be appreciated.
Here is my version of your mergeSort, with the merge function extracted:
def mergeSort (unSortedList):
if len(unSortedList) == 1 :
return unSortedList
else:
midpoint = len(unSortedList)//2
A = mergeSort (unSortedList[:midpoint] )
B = mergeSort (unSortedList[midpoint:] )
return merge(A, B)
def merge(a, b):
i = 0
j = 0
c = []
while True:
if a[i] < b[j]:
c.append(b[j])
j += 1
elif a[i] >= b[j]:
c.append(a[i])
i += 1
if i == len(a):
c.extend(b[j:])
break
if j == len(b):
c.extend(a[i:])
break
return c
Output:
>>> testlist = [2,1,4,2,5,6,8,9]
>>> mergeSort(testlist)
[9, 8, 6, 5, 4, 2, 2, 1]
Couple of things to note:
Appending a list to a list. When you do C.append(A[j:]) you end up with nested lists. That is because A[j:] always returns a list. You either need to use list addition - C += A[j:] - or call extend - C.extend(A[j:])
Missing breaks. When your i or j got to the end of their lists you correctly appended the rest of the other list but you did not terminate the loop. That is what caused the range error because in the next iteration (which should not happen) you tried to get an item at the index equal to the length of the list which is out of range.

Using recursion check each pair in a list, if their sum is negative return True else return False

This is what I have so far.
def negative_sum(L):
if len(L) == 2:
if L[0] + L[1] <0:
return True
else:
return False
else:
return negative_sum(L[0] + negative_sum(L[1:]))
My base case should be correct. My problem is with my final else statement. I need it to check the sum of each pair of the list. I'm having a lot of trouble trying to do this recursively. Any advice is greatly appreciated. Also I cannot use for loops.
A while loop is equivalent to 'tail recursion' withing a single execution frame. Some problems are easier to express with recursion, others with loops. Generating pairs is easily done with nested for loops.
def pairs1(seq``):
n = len(seq)
pairlist = []
for i in range(0, n-1):
for j in range(i+1, n):
pairlist.append((seq[i],seq[j]))
return pairlist
inp = (1, 2, 3)
out = [(1,2), (1,3), (2,3)]
assert pairs1(inp) == out
I would usually use yield instead of pairlist.append. Note the inclusion of a test with the code. As an intermediate step, convert to a single while loop.
def pairs2(seq):
jmax = len(seq) - 1
pairlist = []
i = 0
j = i+1
while i < jmax:
pairlist.append((seq[i],seq[j]))
if j < jmax:
j += 1
else:
i += 1
j = i+1
return pairlist
assert pairs2(inp) == out
Now it is not too hard to convert to using a nested tail recursive closure instead of the while statement.
def pairs3(seq):
jmax = len(seq) - 1
pairlist = []
i = 0
j = i+1
def inner():
nonlocal i, j
if i < jmax:
pairlist.append((seq[i],seq[j]))
if j < jmax:
j += 1
else:
i += 1
j = i+1
inner()
inner()
return pairlist
assert pairs3(inp) == out
Here is a more traditional form.
def pairs4(seq, i, j, pairlist):
jmax = len(seq) - 1
if i < jmax:
pairlist.append((seq[i],seq[j]))
if j < jmax:
return pairs4(seq, i, j+1, pairlist)
else:
return pairs4(seq, i+1, i+2, pairlist)
else:
return pairlist
assert pairs4(inp, 0, 1, []) == out
A strict functionalist would replace pairlist with pairtuple, replace the initial [] with (), and replace the list.append mutation with tuple addition in the recursive calls. The first call would look like this.
return pairs4(seq, i, j+1, pairtuple + ((seq[i],seq[j])))
In Python, all the copying in the additions turns an O(N) function into an O(N**2) function, so I will not do it that way.

Sudoku Generator

So I just made a Sudoku generator that will produce 9x9 matrices. My rows, columns and sub 3x3 matrices should all follow the rules of Sudoku. Only my columns do not follow the rules. Can anyone assist? Here's my code:
import random
maxAttempts = 100 #stops the program after 100 attempts
count = 9999
solCount = 0
while count > maxAttempts:
solCount +=1
# init array
puzzle = []
for i in range(9):
row = []
for j in range(9):
row.append(0)
#print row
puzzle.append(row)
##for r in puzzle:
## print r
# get random value
for row in range(9):
for col in range(9):
thisRow=puzzle[row]
thisCol=[]
for h in range(9):
thisCol.append(puzzle[row][col])
subCol = int(col/3)
subRow = int(row/3)
subMat = []
for subR in range (3):
for subC in range (3):
subMat.append(puzzle[subRow*3 + subR][subCol*3 + subC])
randVal = 0
count = 0
while randVal in thisRow or randVal in thisCol or randVal in subMat:
randVal = random.randint(1,9)
count+=1
if count > maxAttempts: break
puzzle[row][col] = randVal
if count > maxAttempts: break
if count > maxAttempts:
break
for r in puzzle: print r
for h in range(9):
thisCol.append(puzzle[h][col])
Just replace [row], with [h] and you should be fine.