Stagging matrix on Python - python

I have problems trying to stagger a 5x5 array. First I caused a null line to go to the last line of the array (it worked), then I tried to make a line that had the highest index stay below the one with a smaller index, but in the line:
if pivot_index[i] > pivot_index[line_aux] and line_aux < 5 and i < 5:
of the code, the compiler warns that the list index is out of range, but I do not know why (that's the problem), or how to solve it. The algorithm below follows:
import numpy as np
def search_pivot(L):
if (np.nonzero(L)[0]).size == 0:
return -1
else:
return np.nonzero(L)[1][0]
def find_pivot_index(mat):
pivot = []
for i in range(5):
pivot.append(search_pivot(np.array(mat[i])))
return pivot
mat = np.matrix([[0,5,2,7,8],[0,0,4,14,16],[0,0,0,0,0],[2,6,10,16,22],[3,5,8,9,15]]).astype(float)
print("Original array:\n",mat,"\n")
pivot_index = find_pivot_index(mat)
line_aux = 0
for i in range(5):
line_aux = line_aux + 1
if pivot_index[i] > pivot_index[line_aux] and line_aux < 5 and i < 5:
m = mat.tolist()
(m[i],m[linha_aux]) = (m[linha_aux],m[i])
mat = np.matrix(m)
pivot_index = find_pivot_index(mat)
print(mat,"\n")
line_aux = 0
for i in range(5):
line_aux = line_aux + 1
if pivot_index[i] == -1 and line_aux < 5 and i < 5:
m = mat.tolist()
(m[i],m[linha_aux]) = (m[linha_aux],m[i])
mat = np.matrix(m)
pivot_index = find_pivot_index(mat)
print(mat)

The and operator in python is a short-circuit boolean operator
This means that it will only proceed to evaluate the part to the right of and if the left side is True; if the left side is False, since this determines the outcome of the boolean operation completely, the right part does not get evaluated. This allows a programmer to perform a test on the left-hand side, before proceeding to a more 'risky' evaluation that could result in an error.
In your code, you have the test coming after the risky operation. You're checking if linha_aux (whatever that means) is less than 5 after you've attempted to index pivos_indices with a linha_aux of 5 already. (this happens when i = 4, since the first line of your loop is to increment linha_aux.
Therefore:
To "simply" avoid the 'out of index' error, put tests before risky operations:
if line_aux < 5 and i < 5 and pivot_index[i] > pivot_index[line_aux]:
You might want to consider if in fact you intended to increment linha_aux at the end of your loop rather than at the start, if that makes more sense to your algorithm; remember python arrays are 0-indexed

Related

Python Algorithm Problem | How to find a path of desire weight in a connected graph?

Problem
So imagine you are given a m * n matrix like this:
Grid = 4 * 4
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
You want to connect from the top left corner to the bottom right corner and you can only go right or down. In addition, you want to find the operations needed to get the desired sum.
For example:
Script found in Text Book, not clear
def move(m, n, sum):
count = m + n - 1
max_val = m
s = sum
r = []
while max_val > 0:
if count <= 0:
return False, r
least = max_val * ((max_val - 1) / 2)
r.append(max_val)
s -= max_val
count -= 1
while ((count > 0) and (s > least + (count - (max_val - 1)) * (max_val - 1))):
r.append(max_val)
s -= max_val
count -= 1
if s < least:
return False, r
max_val -= 1
return True, r
def combine(m, n, sum):
result, new_res = move(m, n, sum)
new_res.reverse()
for i in range(1, len(new_res)):
if new_res[i] == new_res[i - 1]:
print("R")
else:
print("D")
combine(4, 4, 16)
I don't quite understand the solution.
Can someone explain the Algorithm?
Especially in the function move where it does this check in the while loop:
while ((count > 0) and (s > least + (count - (max_val - 1)) * (max_val - 1))):
Questions
What is the name of this algorithm?
How does this Script Work?
What's the run time (Time complexity)?
Thank you!
So the script isn't well written nor follow best practices, having say that I re adjust it and hopefully is more clear
Source Code
NOTE: I've added to my GitHub Algorithm-Complete-Guide which is under construction, feel free to use it
def move(m, n, weight_limit):
# ==== < CONFIG VARIABLES > ==== #
step_counter = m + n - 1
max_val = m # NOTE: It starts from the last Value (4) and Goes Backwards
path = [] # NOTE: Stores the path (need to reverse it afterwards)
while max_val:
if step_counter <= 0: # NOTE: starting Node so it break Not need to return
break
least = max_val * ((max_val - 1) / 2)
path.append(max_val)
weight_limit -= max_val
step_counter -= 1
if weight_limit < least: # NOTE: Moved it up here because makes more sense to check this first and break
break
# ==== < ROW CHECK | CAN IT GO TO THE LEFT? > ==== #
if step_counter: # NOTE: Moved it as makes it more clear
check_row = least + (step_counter - (max_val - 1)) * (max_val - 1)
while weight_limit > check_row: # FAQ: 1 Footnotes
path.append(max_val)
weight_limit -= max_val
step_counter -= 1
max_val -= 1
return path
def combine(m, n, sum):
path = move(m, n, sum)
path.reverse() # NOTE: Reverse the result Path
result = []
for i in range(1, len(path)):
if path[i] == path[i - 1]: # NOTE: Check if next Value is the same then it moved it to the Right
result.append((path[i], 'Right'))
else:
result.append((path[i], 'Left'))
return result
def prettify_result(res):
for value in res:
print(f'V={value[0]}) {value[1]} |-> ', end='')
if __name__ == '__main__':
path = combine(4, 4, 16)
prettify_result(path)
Explanation
I first thought was a Rat in a Maze problem solved with Backtracking technique of the Algorithm Depth-first_search that runs at Time Complexity: O(2^(n^2)) but after a review I doubt it, and it seems more a kind of Dijkstra's algorithm but I may be wrong. I don't think is Backtracking simple because is not recursive (and never backtracks..) but because it checks for the Node's Weight it seem a Dijkstra's with a given Max-Weight.
Important note, the Maze is solved Upside down, from bottom to top! So It starts at Value 4 and runs backwards! Hence in reality is checking:
Direction UP with more priority.
Direction LEFT is checking at every step (I left a big comment in the script) all the time, if can't go (because costs too much) Then it goes up (going up costs one less because it goes 4, 3, 2, 1)
"function move, what is least + (count - (max_val - 1)) * (max_val - 1)" this I had some hard time to understand as well, basically is just a Math trick and I added it in a variable called check_row to make it more explicit, but basically what it does it check if can go to the Left or not.
At the end of the Algorithm it reverse the list backwards, so that looks like it went from Top to Bottom.
Consideration
The function move()returns always 2 value, first of which if False and stores is in variable result but is not even used. It is pretty weird (seems not got programming practice) and not used anyway so I just removed and replace it with a breakstatements. That's because makes more sense to break in a while loop rather than return. The Function then takes care to return pathat the end.
I remove many while max_val > 0 or similar bool checks against the 0 because is completely redundant and not Pythonic, as Guide realpython.com/python-conditional-statements/
Online Documentations
BACKTRACKING
Rat in a Maze | Backtracking-2 | geeksforgeeks.org
Backtracking Algorithms | geeksforgeeks.org
algorithm-visualizer.org
Algorithm-Complete-Guide
Depth-first search
algorithms/dfs
Algorithm-Complete-Guide
algorithm-visualizer.org
Dijkstra's algorithm
Algorithm-Complete-Guide
algorithm-visualizer.org
. algorithms

Breaking an iterative function in Python before a condition turns False

This is for a school assignment.
I have been tasked to define a function determining the largest square pyramidal number up to a given integer(argument). For some background, these are square pyramidal numbers:
1 = 1^2
5 = 1^2+2^2
14 = 1^2+2^2+3^2
So for a function and parameter largest_square_pyramidal_num(15), the function should return 14, because that's the largest number within the domain of the argument.
I get the idea. And here's my code:
def largest_square_pyramidal_num(n):
sum = 0
i = 0
while sum < n:
sum += i**2
i += 1
return sum
Logically to me, it seemed nice and rosy until I realised it doesn't stop when it's supposed to. When n = 15, sum = 14, sum < n, so the code adds one more round of i**2, and n is exceeded. I've been cracking my head over how to stop the iteration before the condition sum < n turns false, including an attempt at break and continue:
def largest_square_pyramidal_num(n):
sum = 0
for i in range(n+1):
sum += i**2
if sum >= n:
break
else:
continue
return sum
Only to realise it doesn't make any difference.
Can someone give me any advice? Where is my logical lapse? Greatly appreciated!
You can do the following:
def largest_pyr(x):
pyr=[sum([i**2 for i in range(1,k+1)]) for k in range(int(x**0.5)+1)]
pyr=[i for i in pyr if i<=x]
return pyr[-1]
>>>largest_pyr(15)
14
>>> largest_pyr(150)
140
>>> largest_pyr(1500)
1496
>>> largest_pyr(15000)
14910
>>> largest_pyr(150000)
149226
Let me start by saying that continue in the second code piece is redundant. This instruction is used for scenario when you don't want the code in for loop to continue but rather to start a new iteration (in your case there are not more instructions in the loop body).
For example, let's print every number from 1 to 100, but skip those ending with 0:
for i in range(1, 100 + 1):
if i % 10 != 0:
print(i)
for i in range(1, 100 + 1):
if i % 10 == 0:
# i don't want to continue executing the body of for loop,
# get me to the next iteration
continue
print(i)
The first example is to accept all "good" numbers while the second is rather to exclude the "bad" numbers. IMHO, continue is a good way to get rid of some "unnecessary" elements in the container rather than writing an if (your code inside if becomes extra-indented, which worsens readability for bigger functions).
As for your first piece, let's think about it for a while. You while loop terminates when the piramid number is greater or equal than n. And that is not what you really want (yes, you may end up with a piramid number which is equal to n, but it is not always the case).
What I like to suggest is to generate a pyramid number until in exceedes n and then take a step back by removing an extra term:
def largest_square_pyramidal_num(n):
result = 0
i = 0
while result <= n:
i += 1
result += i**2
result -= i ** 2
return result
2 things to note:
don't use sum as a name for the variable (it might confuse people with built-in sum() function)
I swapped increment and result updating in the loop body (such that i is up-to-date when the while loop terminates)
So the function reads like this: keep adding terms until we take too much and go 1 step back.
Hope that makes some sense.
Cheers :)

Binary search stuck in an infinte loop python

My binary search seems to stuck in an infinite loop as it does not output anything for my test data. The second_list is in sorted order and im checking for duplicates from the first list and then adding those duplicates to an empty list. My binary search algorithm performs till there is one element left which I then check is the same as the item, and I would like to keep this structure. I believe the problem is that the right pointer is not decreasing however I cant see why that is.
def detect_duplicates_binary(first_list, second_list):
duplicates_list = []
for item in first_list:
left = 0
right = len(second_list) - 1
while left < right:
midpoint = (left + right) // 2
if second_list[midpoint] > item:
right = midpoint - 1
else:
left = midpoint
if (second_list[left] == item):
duplicates_list.append(item)
return duplicates_list
Pathology
Here's a possible execution sequence that would result in an infinite loop:
>>> left = 10
>>> right = 11
>>> left < right
True
>>> midpoint = (left + right) // 2
>>> midpoint
10
>>> left = midpoint
>>> left
10
>>> # No change!
Suggestion 1
Factor-out just the bisect function and get it tested separately from from the "detect duplicates" code which is a separate algorithm.
Suggestion 2
Use Python's own bisect module -- it is already tested and documented.
Here's a simplified version of its code:
def bisect_right(a, x):
"""Return the index where to insert item x in list a, assuming a is sorted.
The return value i is such that all e in a[:i] have e <= x, and all e in
a[i:] have e > x. So if x already appears in the list, a.insert(x) will
insert just after the rightmost x already there.
"""
lo = 0
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if x < a[mid]: hi = mid
else: lo = mid+1
return lo
Suggestion 3
Increase the right index by 1:
right = len(second_list)
Hope this helps out. Good luck :-)

Nth 1 in a sequence [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
A array of length t has all elements initialized by 1 .Now we can perform two types of queries on the array
to replace the element at ith index to 0 .This query is denoted by 0 index
find and print an integer denoting the index of the kth 1 in array A on a new line; if no such index exists print -1.This query is denoted by 1 k
Now suppose for array of length t=4 all its elements at the beginning are [1,1,1,1] now for query 0 2 the array becomes [1,0,1,1] and for query 1 3 the output comes out to be 4
I have used a brute force approach but how to make the code more efficient?
n,q=4,2
arr=[1]*4
for i in range(q):
a,b=map(int,input().split())
if a==0:
arr[b-1]=0
else:
flag=True
count=0
target=b
for i,j in enumerate(arr):
if j ==1:
count+=1
if count==target:
print(i+1)
flag=False
break
if flag:
print(-1)
I have also tried to first append all the indexes of 1 in a list and then do binary search but pop 0 changes the indices due to which the code fails
def binary_search(low,high,b):
while(low<=high):
mid=((high+low)//2)
#print(mid)
if mid+1==b:
print(stack[mid]+1)
return
elif mid+1>b:
high=mid-1
else:
low=mid+1
n=int(input())
q=int(input())
stack=list(range(n))
for i in range(q):
a,b=map(int,input().split())
if a==0:
stack.pop(b-1)
print(stack)
else:
if len(stack)<b:
print(-1)
continue
else:
low=0
high=len(stack)-1
binary_search(low,high,b)
You could build a binary tree where each node gives you the number of ones that are below and at the left of it. So if n is 7, that tree would initially look like this (the actual list with all ones is shown below it):
4
/ \
2 2
/ \ / \
1 1 1 1
----------------
1 1 1 1 1 1 1 -
Setting the array element at index 4 (zero-based) to 0, would change that tree to:
4
/ \
2 1*
/ \ / \
1 1 0* 1
----------------
1 1 1 1 0*1 1 -
Putting a 0 thus represents a O(log(n)) time complexity.
Counting the number of ones can then also be done in the same time complexity by summing up the node values while descending down the tree in the right direction.
Here is Python code you could use. It represents the tree in a list in breadth-first order. I have not gone to great lengths to further optimise the code, but it has the above time complexities:
class Ones:
def __init__(self, n): # O(n)
self.lst = [1] * n
self.one_count = n
self.tree = []
self.size = 1 << (n-1).bit_length()
at_left = self.size // 2
width = 1
while width <= at_left:
self.tree.extend([at_left//width] * width)
width *= 2
def clear_index(self, i): # O(logn)
if i >= len(self.lst) or self.lst[i] == 0:
return
self.one_count -= 1
self.lst[i] = 0
# Update tree
j = 0
bit = self.size >> 1
while bit >= 1:
go_right = (i & bit) > 0
if not go_right:
self.tree[j] -= 1
j = j*2 + 1 + go_right
bit >>= 1
def get_index_of_ith_one(self, num_ones): # O(logn)
if num_ones <= 0 or num_ones > self.one_count:
return -1
j = 0
k = 0
bit = self.size >> 1
while bit >= 1:
go_right = num_ones > self.tree[j]
if go_right:
k |= bit
num_ones -= self.tree[j]
j = j*2 + 1 + go_right
bit >>= 1
return k
def is_consistent(self): # Only for debugging
# Check that list can be derived by calling get_index_of_ith_one for all i
lst = [0] * len(self.lst)
for i in range(1, self.one_count+1):
lst[self.get_index_of_ith_one(i)] = 1
return lst == self.lst
# Example use
ones = Ones(12)
print('tree', ones.tree)
ones.clear_index(5)
ones.clear_index(2)
ones.clear_index(1)
ones.clear_index(10)
print('tree', ones.tree)
print('lst', ones.lst)
print('consistent = ', ones.is_consistent())
Be aware that this treats indexes as zero-based, while the method get_index_of_ith_one expects an argument that is at least 1 (but it returns a zero-based index).
It should be easy to adapt to your needs.
Complexity
Creation: O(n)
Clear at index: O(logn)
Get index of one: O(logn)
Space complexity: O(n)
Let's start with some general tricks:
Check if the n-th element is too big for the list before iterating. If you also keep a "counter" that stores the number of zeros, you could even check if nth >= len(the_list) - number_of_zeros (not sure if >= is correct here, it seems like the example uses 1-based indices so I could be off-by-one). That way you save time whenever too big values are used.
Use more efficient functions.
So instead of input you could use sys.stdin.readline (note that it will include the trailing newline).
And, even though it's probably not useful in this context, the built-in bisect module would be better than the binary_search function you created.
You could also use for _ in itertools.repeat(None, q) instead of for i in range(q), that's a bit faster and you don't need that index.
Then you can use some more specialized facts about the problem to improve the code:
You only store zeros and ones, so you can use if j to check for ones and if not j to check for zeros. These will be a bit faster than manual comparisons especially in when you do that in a loop.
Every time you look for the nth 1, you could create a temporary dictionary (or a list) that contains the encountered ns + index. Then re-use that dict for subsequent queries (dict-lookup and list-random-access is O(1) while your search is O(n)). You could even expand it if you have subsequent queries without change in-between.
However if a change happens you either need to discard that dictionary (or list) or update it.
A few nitpicks:
The variable names are not very descriptive, you could use for index, item in enumerate(arr): instead of i and j.
You use a list, so arr is a misleading variable name.
You have two i variables.
But don't get me wrong. It's a very good attempt and the fact that you use enumerate instead of a range is great and shows that you already write pythonic code.
Consider something akin to the interval tree:
root node covers the entire array
children nodes cover left and right halves of the parent range respectively
each node holds the number of ones in its range
Both replace and search queries could be completed in logarithmic time.
Refactored with less lines, so more efficient in terms of line count but run time probably the same O(n).
n,q=4,2
arr=[1]*4
for i in range(q):
query, target = map(int,input('query target: ').split())
if query == 0:
arr[target-1] = 0
else:
count=0
items = enumerate(arr, 1)
try:
while count < target:
index, item = next(items)
count += item
except StopIteration as e:
index = -1
print(index)
Assumes arr contains ONLY ones and zeroes - you don't have to check if an item is one before you add it to count, adding zero has no affect.
No flags to check, just keep calling next on the enumerate object (items) till you reach your target or the end of arr.
For runtime efficiency, using an external library but basically the same process (algorithm):
import numpy as np
for i in range(q):
query, target = map(int,input('query target: ').split())
if query == 0:
arr[target-1] = 0
else:
index = -1
a = np.array(arr).cumsum() == target
if np.any(a):
index = np.argmax(a) + 1
print(index)

How to express j+1 in this case?

I'm writing a piece of code to filter some data, and I've come across a problem. I currently have:
def accountforfilter(wavelength, flux, filterwavelength, throughput):
filteredwavelength=[]
filteredflux=[]
for i in wavelength:
for j in filterwavelength:
if wavelength==filterwavelength:
j=filterwavelength.index(wavelength)
filteredwavelength.append(wavelength)
filteredflux.append(flux*throughput)
elif filterwavelength<wavelength<filterwavelength(j+1):
filteredwavelength.append(wavelength)
filteredflux.append(flux*f(wavelength))
#f is a function that interpolates using y=mx+c when wavelength and filterwavelength are not the same
elif wavelength<filterwavelength:
i+=1
elif wavelength>filterwavelength:
j+=1
return filteredwavelength, filteredflux
The problem I have is with the line:
elif filterwavelength<wavelength<filterwavelength(j+1):
This line doesn't work, I get the error:
TypeError: 'list' object is not callable
If I change the round brackets to square brackets, i.e.
elif filterwavelength<wavelength<filterwavelength[j+1]:
I get the error:
TypeError: list indices must be integers, not float
I'm not sure how to express what I mean in another way.
You should really use more descriptive variable names to avoid numerous errors that exist in your code.
I assume that in your function parameters, wavelength and filterwavelength are lists. So let’s make that clear by using plural names:
def accountforfilter(wavelengths, flux, filterwavelengths, throughput)
As soon as you do that, comparison like these don’t make much sense anymore:
if wavelengths == filterwavelengths:
elif filterwavelengths < wavelengths < filterwavelengths[j+1]:
Especially in the second comparison, you are comparing a list, with a list, with a list item.
Finally, when using for, the loop variable (your i and j) is set to individual list items, not indexes. So you definitely can’t tread those values as indexes. To reflect that, you should name them appropriately:
# one wavelength out of all wavelengths
for wavelength in wavelengths:
# one filterwavelength out of all filterwavelengths
for filterwavelength in filterwavelengths:
Also note, that when using for, you can’t change the way they are iterating. Every iteration, the next item will be handled; you can’t skip or repeat one item (as you seem to be trying with your i += 1 and j += 1. If you need to do that, you will have to use a classic while loop instead:
i, j = 0, 0
while i < len(wavelengths):
while j < len(filterwavelengths):
if condition:
i += 1
else:
j += 1
So, in total, the function might look like this (tried my best to understand what’s going on):
def accountforfilter (wavelengths, flux, filterwavelengths, throughput):
filteredWavelengths = []
filteredFluxes = []
i, j = 0, 0
while i < len(wavelengths):
wavelength = wavelengths[i]
while j < len(filterwavelengths):
filterwavelength = filterwavelengths[j]
if wavelength == filterwavelength:
filteredWavelengths.append(wavelength)
filteredFluxes.append(flux * throughput)
elif j + 1 < len(filterwavelengths) and filterwavelength < wavelength < filterwavelengths[j + 1]:
filteredWavelengths.append(wavelength)
filteredFluxes.append(flux * f(wavelength))
if wavelength < filteredwavelength:
i += 1
else:
j += 1
# increase j even when both are equal, otherwise we end up in an infinite loop
return filteredWavelengths, filteredFluxes
A few things: This statement:
for i in wavelength:
produces a sequence of the values in the wavelength list, not indexes to them.
If you want the indexes as well, use
for i, wv in enumerate(wavelength):
...
Similarly for the j loop. Also, this comparison: wavelength==filterwavelength is dangerous if the values are floating point. It's a little hard to advise further without more information about what you're trying to acheive.

Categories

Resources