Iterate over indices with constant sum in Python - python

I am working with polynomials and have to perform some operation where my looping variables have a sum inferior to some constant d.
Right now I have
for i in range(0, d):
for j in range(i, d):
for k in range(j, d):
which seems a bit ugly to me.
Is there some function, probably in itertools, allowing me to iterate for i, j, k in foo(d) ?

You can write your own. Here's a brute force way for 3 variables:
def constant_sum(s):
for i in range(s+1):
for j in range(s-i+1):
k = s - i - j
yield i,j,k
def inferior_sum(s):
for i in range(s+1):
for j in range(s+1):
if i+j >= s:
break
for k in range(s+1):
if i+j+k < s:
yield i,j,k
else:
break
for i,j,k in constant_sum(3):
print(i,j,k)
print()
for i,j,k in inferior_sum(3):
print(i,j,k)
Output:
0 0 3
0 1 2
0 2 1
0 3 0
1 0 2
1 1 1
1 2 0
2 0 1
2 1 0
3 0 0
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 2 0
1 0 0
1 0 1
1 1 0
2 0 0
Here are recursive versions that can do any number of variables(n) for any sum(s)...lightly tested:
def constant_sum(n,s):
if n == 1:
yield [s]
else:
for i in range(s+1):
for r in constant_sum(n-1,s-i):
yield [i] + r
def inferior_sum(n,s):
if n == 1:
for i in range(s):
yield [i]
else:
for i in range(s):
for r in inferior_sum(n-1,s-i):
yield [i] + r
for x in constant_sum(3,3):
print(*x)
print()
for x in inferior_sum(3,3):
print(*x)
Output:
0 0 3
0 1 2
0 2 1
0 3 0
1 0 2
1 1 1
1 2 0
2 0 1
2 1 0
3 0 0
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 2 0
1 0 0
1 0 1
1 1 0
2 0 0

The itertools/functional way would be something like:
from itertools import product
inferior_sum3 = filter(lambda x: sum(x)<3, product(range(4),range(4),range(4)))
for permu in inferior_sum3:
print(permu)
Output:
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 1, 0)
(0, 1, 1)
(0, 2, 0)
(1, 0, 0)
(1, 0, 1)
(1, 1, 0)
(2, 0, 0)

Related

Counting repeated sequences in transition table

I'm using the following function to generate a transition table:
import numpy as np
import pandas as pd
def make_table(allSeq):
n = max([ max(s) for s in allSeq ]) + 1
arr = np.zeros((n,n), dtype=int)
for seq in allSeq:
ind = (seq[1:], seq[:-1])
arr[ind] += 1
return pd.DataFrame(arr).rename_axis(index='Next', columns='Current')
However, my result is incorrect:
list1 = [1,2,3,4,5,4,5,4,5]
list2 = [4,5,4,5]
make_table([list1, list2])
Current 0 1 2 3 4 5
Next
0 0 0 0 0 0 0
1 0 0 0 0 0 0
2 0 1 0 0 0 0
3 0 0 1 0 0 0
4 0 0 0 1 0 2
5 0 0 0 0 2 0
For example, the transition 4->5 should be counted 5 times, but it's only counted once per sequence (2). I know the issue is the arr[ind] += 1 line, but I just can't figure it out! Do I nest another loop, or is there a slick way to add the total number of instances at once? Thanks!
Figured it out! Switched to the following:
def make_table(allSeq):
n = max([ max(s) for s in allSeq ]) + 1
arr = np.zeros((n,n), dtype=int)
for seq in allSeq:
for i,j in zip(seq[1:],seq[:-1]):
ind = (i,j)
arr[ind] += 1
return pd.DataFrame(arr).rename_axis(index='Next', columns='Current')
Another loop seems like the easiest solution, with a bit of a twist of using zip:
import numpy as np
import pandas as pd
def make_table(allSeq):
n = max([ max(s) for s in allSeq ]) + 1
arr = np.zeros((n,n), dtype=int)
for seq in allSeq:
ind = zip(seq[1:], seq[:-1])
for i in ind:
arr[i] += 1
return pd.DataFrame(arr).rename_axis(index='Next', columns='Current')
list1 = [1,2,3,4,5,4,5,4,5]
list2 = [4,5,4,5]
make_table([list1, list2])
returns
Next 0 1 2 3 4 5
------ --- --- --- --- --- ---
0 0 0 0 0 0 0
1 0 0 0 0 0 0
2 0 1 0 0 0 0
3 0 0 1 0 0 0
4 0 0 0 1 0 3
5 0 0 0 0 5 0

Python: Writing a matrix with different values depending of how far is from a point (i,j)

Help me out with this code! As Input I have N: matrix size. i: point's row. j: point's column. P: point's magnitude. Each time I move away point (i,j) the magnitude will decrease -1. So if my input is N = 7, i = 3, j = 3, P = 3, my output would look like this:
0 0 0 0 0 0 0
0 1 1 1 1 1 0
0 1 2 2 2 1 0
0 1 2 3 2 1 0
0 1 2 2 2 1 0
0 1 1 1 1 1 0
0 0 0 0 0 0 0
I can't figure out how to write the correct value in each position :( help me out! Here's the code that I tried -->
Not a beautiful or efficient solution, but gets the work done:
N, i, j, P = 7, 3, 3, 3
M = [[0] * N for i in range(N)]
for row in range(N):
for col in range(N):
M[row][col] = P - max(abs(row - i), abs(col - j))

Find all the blocks

I am very new to python and coding. I have this homework that I have to do:
You will receive on the first line the rows of the matrix (n) and on the next n lines you will get each row of the matrix as a string (zeros and ones separated by a single space). You have to calculate how many blocks you have (connected ones horizontally or diagonally) Here are examples:
Input:
5
1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 1 1
0 0 0 1 1
Output:
2
Input:
6
1 1 0 1 0 1
0 1 1 1 1 1
0 1 0 0 0 0
0 1 1 0 0 0
0 1 1 1 1 0
0 0 0 1 1 0
Output:
1
Input:
4
0 1 0 1 1 0
1 0 1 1 0 1
1 0 0 0 0 0
0 0 0 1 0 0
Output:
5
the code I came up with for now is :
n = int(input())
blocks = 0
matrix = [[int(i) for i in input().split()] for j in range(n)]
#loop or something to find the blocks in the matrix
print(blocks)
Any help will be greatly appreciated.
def valid(y,x):
if y>=0 and x>=0 and y<N and x<horizontal_len:
return True
def find_blocks(y,x):
Q.append(y)
Q.append(x)
#search around 4 directions (up, right, left, down)
dy = [0,1,0,-1]
dx = [1,0,-1,0]
# if nothing is in Q then terminate counting block
while Q:
y = Q.pop(0)
x = Q.pop(0)
for dir in range(len(dy)):
next_y = y + dy[dir]
next_x = x + dx[dir]
#if around component is valid range(inside the matrix) and it is 1(not 0) then include it as a part of block
if valid(next_y,next_x) and matrix[next_y][next_x] == 1:
Q.append(next_y)
Q.append(next_x)
matrix[next_y][next_x] = -1
N = int(input())
matrix = []
for rows in range(N):
row = list(map(int, input().split()))
matrix.append(row)
#row length
horizontal_len = len(matrix[0])
blocks = 0
#search from matrix[0][0] to matrix[N][horizontal_len]
for start_y in range(N):
for start_x in range(horizontal_len):
#if a number is 1 then start calculating
if matrix[start_y][start_x] == 1:
#make 1s to -1 for not to calculate again
matrix[start_y][start_x] = -1
Q=[]
#start function
find_blocks(start_y, start_x)
blocks +=1
print(blocks)
I used BFS algorithm to solve this question. The quotations are may not enough to understand the logic.
If you have questions about this solution, let me know!

Python: Constructing & Printing matrices

I need to create a matrix that calculates the LCS and then print it out. This is my code, but I'm having trouble with the print function (don't know how to get the LCSmatrix values into the printing)
def compute_LCS(seqA, seqB):
for row in seqA:
for col in seqB:
if seqA[row] == seqB[col]:
if row==0 or col==0:
LCSmatrix(row,col) = 1
else:
LCSmatrix(row,col) = LCS(row-1,col-1) + 1
else:
LCSmatrix(row,col) = 0
return LCSmatrix
def printMatrix(parameters...):
print ' ',
for i in seqA:
print i,
print
for i, element in enumerate(LCSMatrix):
print i, ' '.join(element)
matrix = LCSmatrix
print printMatrix(compute_LCS(seqA,seqB))
Any help would be much appreciated.
Try this:
seqA='AACTGGCAG'
seqB='TACGCTGGA'
def compute_LCS(seqA, seqB):
LCSmatrix = [len(seqB)*[0] for row in seqA]
for row in range(len(seqB)):
for col in range(len(seqA)):
if seqB[row] == seqA[col]:
if row==0 or col==0:
LCSmatrix[row][col] = 1
else:
LCSmatrix[row][col] = LCSmatrix[row-1][col-1] + 1_
else:
LCSmatrix[row][col] = 0
return LCSmatrix
def printMatrix(seqA, seqB, LCSmatrix):
print ' '.join('%2s' % x for x in ' '+seqA)
for i, element in enumerate(LCSmatrix):
print '%2s' % seqB[i], ' '.join('%2i' % x for x in element)
matrix = compute_LCS(seqA, seqB)
printMatrix(seqA, seqB, matrix)
The above produces:
A A C T G G C A G
T 0 0 0 1 0 0 0 0 0
A 1 1 0 0 0 0 0 1 0
C 0 0 2 0 0 0 1 0 0
G 0 0 0 0 1 1 0 0 1
C 0 0 1 0 0 0 2 0 0
T 0 0 0 2 0 0 0 0 0
G 0 0 0 0 3 1 0 0 1
G 0 0 0 0 1 4 0 0 1
A 1 1 0 0 0 0 0 1 0

Python, and The Game of Life Rules

Okay, so i finally get this to print, and actually do something, but the rules are not applying right? I've tried messing with the rules, but can't seem to get them to print out right, here's the snip of my rules:
nCount = 0
for i in range(x-1,x+2):
for j in range(y-1,y+2):
if not(i == x and j == y):
nCount += int(mat[i][j])
if(nCount < 2 or nCount > 3):
return 0
elif(nCount == 2 or nCount == 3):
return 1
else:
return mat[i][j]
I've tested with a regular 5x5 with 3 1's in the middle to act as an oscillator but instead of oscillating it fills the 5x5 edges with zeros like a square box then stops
Here is the rest of my coding:
import time
import os
def buildMatrix(fname):
fp = open(fname, "r")
row = fp.readlines()
matrix = []
for i in range(0, len(row), 1):
token = row[i].split(" ")
token[-1] = token[-1].replace('\n', ' ')
matrix.append(token)
fp.close()
return matrix
def getRows(mat):
return len(mat)
def getCols(mat):
return len(mat[0])
def printGen(mat): #this is what i use for printing
os.system('clear')
for i in range(0, len(mat), 1):
for j in range(0, len(mat[0]), 1):
if(mat[i][j] == 1):
print("#", sep=" ", end=" ")
else:
print(" ", sep=" ", end=" ")
print()
def nextGen(cur, nxt): #use this to update to the next matrix
for i in range(0, len(cur)-1, 1):
for j in range(0, len(cur[0])-1, 1):
nxt[i][j] = neighbors(i, j, cur)
return nxt
def neighbors(x, y, mat):
nCount = 0
for i in range(x-1,x+2):
for j in range(y-1,y+2):
if not(i == x and j == y):
nCount += int(mat[i][j])
if(nCount < 2 or nCount > 3):
return 0
elif(nCount == 2 or nCount ==3):
return 1
else:
return mat[i][j]
This isnt all my code, as im still importing all this to another repo and running it from that repo, but the other part i have done
elif(nCount == 2,3):
This doesn't do what you want. This builds a 2-element tuple whose first element is the value of nCount == 2, and whose second element is 3, then converts this tuple to a boolean to decide which way to go. If you wanted to check whether nCount was equal to either 2 or 3, you could use
elif nCount in (2, 3):
but it's redundant, since nCount must be one of those for control flow to reach the elif. Of course, this isn't correct for implementing the rules of Life; what you want is
elif nCount == 3:
A cell keeps its current live/dead status if surrounded by 2 other live cells. There have to be exactly 3 live cells around it for it to be alive in the next generation regardless of its current life status.
It looks like your code isn't making a copy first, so the results of a birth or death are effecting themselves. Try with a copy:
import numpy
# this function does all the work
def play_life(a):
xmax, ymax = a.shape
b = a.copy() # copy current life grid
for x in range(xmax):
for y in range(ymax):
n = numpy.sum(a[max(x - 1, 0):min(x + 2, xmax), max(y - 1, 0):min(y + 2, ymax)]) - a[x, y]
if a[x, y]:
if n < 2 or n > 3:
b[x, y] = 0 # living cells with <2 or >3 neighbors die
elif n == 3:
b[x, y] = 1 # dead cells with 3 neighbors ar born
return(b)
life = numpy.zeros((5, 5), dtype=numpy.byte)
# place starting conditions here
life[2, 1:4] = 1 # middle three in middle row to 1
# now let's play
print(life)
for i in range(3):
life = play_life(life)
print(life)
I also used numpy for speed. Note that the case for a live cell with 2 or 3 neighbors is taken care of when the copy is made. Here are the results of this test case:
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 0 0 0]]
Now, if you don't have numpy, then you can use a "2D" array like this:
# this function does all the work
def play_life(a):
xmax = len(a)
ymax = len(a[0])
b = [[cell for cell in row] for row in life]
for x in range(xmax):
for y in range(ymax):
n = 0
for i in range(max(x - 1, 0), min(x + 2, xmax)):
for j in range(max(y - 1, 0), min(y + 2, ymax)):
n += a[i][j]
n -= a[x][y]
if a[x][y]:
if n < 2 or n > 3:
b[x][y] = 0 # living cells with <2 or >3 neighbors die
elif n == 3:
b[x][y] = 1 # dead cells with 3 neighbors ar born
return(b)
# this function just prints the board
def show_life(a):
print('\n'.join([' '.join([str(cell) for cell in row]) for row in life]) + '\n')
# create board
x_size, y_size = (5, 5)
life = [[0 for y in range(y_size)] for x in range(x_size)]
# place starting conditions here
for x in range(1, 4): life[x][2] = 1 # middle three in middle row to 1
# now let's play
show_life(life)
for i in range(3):
life = play_life(life)
show_life(life)
That outputs the following for the test case:
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0

Categories

Resources