My goal is to iterate over the pairs [a,b] a coprime to b and a+b<=n. For example, if n=8, I want to iterate over [1, 2], [2, 3], [3, 4], [3, 5], [1, 3], [2, 5], [1, 4], [1, 5], [1, 6], [1, 7].
My first thought was a recursive function using the Stern-Brocot tree:
def Stern_Brocot(n,a=0,b=1,c=1,d=1):
if(a+b+c+d>n):
return 0
x=Stern_Brocot(n,a+c,b+d,c,d)
y=Stern_Brocot(n,a,b,a+c,b+d)
if(x==0):
if(y==0):
return [a+c,b+d]
else:
return [a+c]+[b+d]+y
else:
if(y==0):
return [a+c]+[b+d]+x
else:
return [a+c]+[b+d]+x+y
As expected,
>>> Stern_Brocot(8)
[1, 2, 2, 3, 3, 4, 3, 5, 1, 3, 2, 5, 1, 4, 1, 5, 1, 6, 1, 7]
And for n<=995, it works well. But suddenly at n>=996, it gives this error:
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
a=Stern_Brocot(996)
File "C:\Users\Pim\Documents\C Programmeren en Numerieke Wisk\Python\PE\PE127.py", line 35, in Stern_Brocot
y=Stern_Brocot(n,a,b,a+c,b+d)
...
File "C:\Users\Pim\Documents\C Programmeren en Numerieke Wisk\Python\PE\PE127.py", line 35, in Stern_Brocot
y=Stern_Brocot(n,a,b,a+c,b+d)
RuntimeError: maximum recursion depth exceeded in comparison
And since I want n to equal 120000, this approach won't work.
So my question is: what would be a good approach to iterate over parts of the Stern_Brocot tree? (if there's another way to iterate over coprime integers, that'd be good as well).
Here's an non-recursive implementation
def Stern_Brocot(n):
states = [(0, 1, 1, 1)]
result = []
while len(states) != 0:
a, b, c, d = states.pop()
if a + b + c + d <= n:
result.append((a+c, b+d))
states.append((a, b, a+c, b+d))
states.append((a+c, b+d, c, d))
return result
Before defining Stern_Brocot, add sys.setrecursionlimit(120000). This will set the program's recursion limit to 120000.
So, instead, you can do this:
import sys
sys.setrecursionlimit(120000)
def Stern_Brocot(n,a=0,b=1,c=1,d=1):
if(a+b+c+d>n):
return 0
x=Stern_Brocot(n,a+c,b+d,c,d)
y=Stern_Brocot(n,a,b,a+c,b+d)
if(x==0):
if(y==0):
return [a+c,b+d]
else:
return [a+c]+[b+d]+y
else:
if(y==0):
return [a+c]+[b+d]+x
else:
return [a+c]+[b+d]+x+y
Related
I tried to write the code to solve Nuts & Bolts Problem by using quicksort(?), but it does not work well. The most confusing part for me is the returning point of recursion. How can I modify it and is there any tip to considering the returning point of recursion?
Nuts & Bolts Problem:
Given a set of n nuts of different sizes and n bolts of different sizes. There is a one-one mapping between nuts and bolts. Match nuts and bolts efficiently.
Constraint: Comparison of a nut to another nut or a bolt to another bolt is not allowed. It means nut can only be compared with bolt and bolt can only be compared with nut to see which one is bigger/smaller.
Other way of asking this problem is, given a box with locks and keys where one lock can be opened by one key in the box. We need to match the pair.
def smallerThanPartition(nuts, p):
lowN = []
for i in range(0, len(nuts)):
if p > nuts[i]:
lowN.append(nuts[i])
return lowN
def largerThanPartition(nuts, p):
highN = []
for i in range(0, len(nuts)):
if p < nuts[i]:
highN.append(nuts[i])
return highN
def ALG5(nuts, bolts, partition):
if(len(bolts) <= 1):
print('nuts + bolts = '+ str(nuts + bolts))
return nuts + bolts
else:
lowB = []
highB = []
a = []
b = []
lowN = []
highN = []
for i in range(0, len(nuts)):
if nuts[partition] > bolts[i]:
lowB.append(bolts[i])
lowN = smallerThanPartition(nuts, nuts[partition])
else:
highB.append(bolts[i])
highN = largerThanPartition(nuts, nuts[partition])
a = ALG5(lowN, lowB, len(lowN) / 2)
b = ALG5(highN, highB, len(highN) / 2)
return a + nuts[partition] + b
if __name__ == "__main__":
nuts = [1, 3, 5, 2, 44, 6]
bolts = [5, 2, 6, 44, 1, 3]
n = len(nuts)
partition = n / 2
print(ALG5(nuts, bolts, partition))
the result of the above code is
[1, 1, 2, 3, 2, 5, 5, 6, 44, 44]
[1, 3, 5, 2, 44, 6]
[5, 2, 6, 44, 1, 3]
the ideal result is
[1, 2, 3, 5, 6, 44]
[1, 3, 5, 2, 44, 6]
[5, 2, 6, 44, 1, 3]
My most recent lab assignment has me trying to implement a Greedy algorithm for the 0/1 Knapsack problem, and print out the contents of the knapsack along with the total value of the knapsack. So far, I was able to get it to output the total value of the knapsack without issue, but I'm having trouble with outputting what items went into the knapsack.
#class definitions for the greedy approach
class Item:
def __init__(self,weight,value):
self.weight = weight
self.value = value
self.price_kg = value / weight
def __repr__(self):
return f"Item(weight={self.weight}, value={self.value},v/w={self.price_kg})\n"
class Knapsack:
def __init__(self,max_weight,items):
self.max_weight = max_weight
self.items = items
self.contents = list()
def fillGreedy(self):
self.items.sort(key=lambda x: x.price_kg, reverse=True)#sorts the items by weight/value
for i in self.items:
self.contents.append(i)#Tries putting the item in the bag
if sum(i.weight for i in self.contents) > self.max_weight:
self.contents.remove(i)#Removes the item it is too heavy for the bag
elif sum(i.weight for i in self.contents) == self.max_weight:#finds an optimal configuration for the bag
return sum(i.value for i in self.contents)
return sum(i.value for i in self.contents)
#main method
max_weights = [10, 13, 15, 30, 30]
weights = [
[4, 5, 7],
[6, 5, 7, 3, 1],
[2, 3, 5, 5, 3, 7],
[10, 13, 17, 15],
[5, 4, 7, 6, 3, 4, 2, 1, 7, 6]
]
values = [
[2, 3, 4],
[7, 3, 4, 4, 3],
[3, 4, 10, 9, 6, 13],
[21, 17, 30, 23],
[3, 1, 3, 2, 1, 3, 2, 3, 1, 4]
]
for i in range(len(max_weights)):
items = list()
for j in range(len(weights[i])):
items.append(Item(weights[i][j], values[i][j])) #adds the contents of the arrays to the Items list
i
ks = Knapsack(max_weights[i], items)
v1 = ks.fillGreedy()
print(f"Total value = {v1}")
#print(items)
So far, I tried printing out the contents of the ks and v1 objects, but that only gives the memory addresses of the objects. I tried printing out the 'items' list itself after iterating through the fillGreedy method, but it prints out all the contents of the list and not the ones in the knapsack itself. I also tried doing something in the fillGreedy method that would print the item that was just added, but it ended up causing conflicts. I'm unsure where to continue from here. Is there a way to print out the items of the knapsack using this approach?
Welcome to the site.
You already have a collection of the selected items inside the Knapsack object, so you could iterate over ks.contents and print out the contents or whatever is needed from there...
for item in ks.contents:
print(item)
I want te creates a function which add elements to list. I want it to stop when it comes to border of range()
I got this:
def get_values(i,n):
d =[]
for x in range(n):
d.append(next(i))
return d
i = iter(range(10))
print((get_values(i,5)))
print((get_values(i,4)))
print((get_values(i,2)))
It gives me:
[0, 1, 2, 3, 4]
[5, 6, 7, 8]
Traceback (most recent call last):
File "/Users/user/Documents/untitled1/lol.py", line 17, in <module>
print((get_values(i,2)))
File "/Users/user/Documents/untitled1/lol.py", line 4, in get_values
d.append(next(i))
StopIteration
But I want to achive this:
>>> i = iter(range(10))
>>> get_values(i, 3)
[0, 1, 2]
>>> get_values(i, 5)
[3, 4, 5, 6, 7]
>>> get_values(i, 4)
[8, 9]
>>> get_values(i, 4)
[]
How can I control the loop to put just elements from range() of i?
just listen to the error and stop iteration when there is a error and break out of the loop:
def get_values(i,n):
d =[]
for x in range(n):
try:
d.append(next(i))
except StopIteration:
break
return d
The only way you can check if you can continue is to listen to the StopIteration exception. Here is another solution I thought can be handy:
def get_values(i, n):
d = []
try:
for _ in range(n):
d.append(next(i))
finally:
return d
Look for https://www.geeksforgeeks.org/python-next-method/ to learn more about arguments you can pass to next statement
def get_values(i,n):
d =[]
for x in range(n):
temp=next(i,'end')
if temp=="end":
break
d.append(temp)
return d
i = iter(range(10))
print((get_values(i,5)))
print((get_values(i,4)))
print((get_values(i,2)))
Output
[0, 1, 2, 3, 4]
[5, 6, 7, 8]
[9]
I was assigned to write a function that accept two lists and returns True if the other list is a cyclic permutation of the other.
I wrote a function that accepts two lists and changes between the first and the last place. After that i wrote a function that calls the first function using a for loop and returns True at the end of the loop if it was true for each i.
I tries running the code and ive encountered several error messages:
File "C:/WinPython-64bit-3.5.2.2Qt5/settings/.spyder-py3/temp.py", line 13, in cyclic
if change_position(lst1, lst2):
File "C:/WinPython-64bit-3.5.2.2Qt5/settings/.spyder-py3/temp.py", line 5, in change_position
lst3[0] = lst4[len(lst4)]
Here is my code:
def change_position(lst3, lst4):
if len(lst3) != len(lst4):
print(False)
else:
lst3[0] = lst4[len(lst4)]
def cyclic(lst1, lst2):
if len(lst1) != len(lst2):
print(False)
else:
for i in range(len(lst1)):
if change_position(lst1, lst2):
print(True)
else:
print(False)
cyclic([1, 2, 3, 4], [4, 1, 2, 3])
Does anyone know how i can fix this so the function will work?
Thanks in advance for all of your help.
No need to reorder your list, only index computations will do
def is_cyc_perm (list1, list2):
if len (list1) == len (list2):
for shift in range (len (list1)):
for i in range (len (list1)):
if list1 [i] != list2 [(i + shift) % len (list1)]:
break
else:
return True
else:
return False
else:
return False
print (is_cyc_perm ([8, 2, 5, 7], [8, 2, 5, 7]))
print (is_cyc_perm ([7, 8, 2, 5], [8, 2, 5, 7]))
print (is_cyc_perm ([2, 5, 7, 8], [8, 2, 5, 7]))
print (is_cyc_perm ([8, 5, 2, 7], [8, 2, 5, 7]))
print (is_cyc_perm ([7, 2, 5, 8], [8, 2, 5, 7]))
print (is_cyc_perm ([8, 2, 5, 3], [8, 2, 5, 7]))
The list index starts with 0, you should use range(0, len(list)-1).
def change_position(lst3, lst4):
if len(lst3) != len(lst4):
print(False)
else:
lst3[0] = lst4[len(lst4)-1]
def cyclic(lst1, lst2):
if len(lst1) != len(lst2):
print(False)
else:
for i in range(len(lst1)-1):
if change_position(lst1, lst2):
print(True)
else:
print(False)
Rotating a double linked list is a quick operation with pointers. You can simply try all rotations if there is a match.
The collections module also provides Counter which can be used for a quick test if both lists have the same count of the same elements. It is just a stronger version of the obvious same length check.
import collections
def is_cyc_perm(seq1, seq2):
mset1 = collections.Counter(seq1)
mset2 = collections.Counter(seq2)
if mset1 != mset2:
return False
size = len(seq1)
deq1 = collections.deque(seq1)
deq2 = collections.deque(seq2)
for _ in range(size):
deq2.rotate()
if deq1 == deq2:
return True
return False
from copy import*
a=[1,2,3,4]
c={'a':'aaa'}
print c
#{'a': 'aaa'}
b=deepcopy(a,c)
print b
print c
# print {'a': 'aaa', 10310992: 3, 10310980: 4, 10311016: 1, 11588784: [1, 2, 3, 4, [1, 2, 3, 4]], 11566456: [1, 2, 3, 4], 10311004: 2}
why c print that
Please try to use the code, rather than text, because my English is not very good, thank you
in django.utils.tree.py
def __deepcopy__(self, memodict):
"""
Utility method used by copy.deepcopy().
"""
obj = Node(connector=self.connector, negated=self.negated)
obj.__class__ = self.__class__
obj.children = deepcopy(self.children, memodict)
obj.subtree_parents = deepcopy(self.subtree_parents, memodict)
return obj
import copy
memo = {}
x1 = range(5)
x2=range(6,9)
x3=[2,3,4,11]
y1 = copy.deepcopy(x1, memo)
y2=copy.deepcopy(x2, memo)
y3=copy.deepcopy(x3,memo)
print memo
print id(y1),id(y2),id(y3)
y1[0]='www'
print y1,y2,y3
print memo
print :
{10310992: 3, 10310980: 4, 10311016: 1, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10311004: 2}
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10310932: 8, 10311004: 2}
11572408 11581280 11580960
['www', 1, 2, 3, 4] [6, 7, 8] [2, 3, 4, 11]
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: ['www', 1, 2, 3, 4], 10310932: 8, 10311004: 2}
No one above gave a good example of how to use it.
Here's what I do:
def __deepcopy__(self, memo):
copy = type(self)()
memo[id(self)] = copy
copy._member1 = self._member1
copy._member2 = deepcopy(self._member2, memo)
return copy
Where member1 is an object not requiring deepcopy (like a string or integer), and member2 is one that does, like another custom type or a list or dict.
I've used the above code on highly tangled object graphs and it works very well.
If you also want to make your classes pickleable (for file save / load), there is not analogous memo param for getstate / setstate, in other words the pickle system somehow keeps track of already referenced objects, so you don't need to worry.
The above works on PyQt5 classes that you inherit from (as well as pickling - for instance I can deepcopy or pickle a custom QMainWindow, QWidget, QGraphicsItem, etc.)
If there is some initialization code in your constructor that creates new objects, for instance a CustomWidget(QWidget) that creates a new CustomScene(QGraphicsScene), but you'd like to pickle or copy the scene from one CustomWidget to a new one, then one way is to make a new=True parameter in your __init__ and say:
def __init__(..., new=True):
....
if new:
self._scene = CustomScene()
def __deepcopy__(self, memo):
copy = type(self)(..., new=False)
....
copy._scene = deepcopy(self._scene, memo)
....
That ensures you don't create a CustomScene (or some big class that does a lot of initializing) twice! You also should use the same setting (new=False) in your __setstate__ method, eg.:
def __setstate__(self, data):
self.__init__(...., new=False)
self._member1 = data['member 1']
.....
There are other ways to get around the above, but this is the one I converged to and use frequently.
Why did I talk about pickling as well? Because you will want both in any application typically, and you maintain them at the same time. If you add a member to your class, you add it to setstate, getstate, and deepcopy code. I would make it a rule that for any new class you make, you create the above three methods if you plan on doing copy / paste an file save / load in your app. Alternative is JSON and save / loading yourself, but then there's a lot more work for you to do including memoization.
So to support all the above, you need __deepcopy__, __setstate__, and __getstate__ methods and to import deepcopy:
from copy import deepcopy
, and when you write your pickle loader / saver functions (where you call pickle.load()/ pickle.dump() to load / save your object hierarchy / graph) do import _pickle as pickle for the best speeds (_pickle is some faster C impl which is usually compatible with your app requirements).
It's the memo dict, where id-to-object correspondence is kept to reconstruct complex object graphs perfectly. Hard to "use the code", but, let's try:
>>> import copy
>>> memo = {}
>>> x = range(5)
>>> y = copy.deepcopy(x, memo)
>>> memo
{399680: [0, 1, 2, 3, 4], 16790896: 3, 16790884: 4, 16790920: 1,
438608: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 16790932: 0, 16790908: 2}
>>>
and
>>> id(x)
399680
>>> for j in x: print j, id(j)
...
0 16790932
1 16790920
2 16790908
3 16790896
4 16790884
so as you see the IDs are exactly right. Also:
>>> for k, v in memo.items(): print k, id(v)
...
399680 435264
16790896 16790896
16790884 16790884
16790920 16790920
438608 435464
16790932 16790932
16790908 16790908
you see the identity for the (immutable) integers.
So here's a graph:
>>> z = [x, x]
>>> t = copy.deepcopy(z, memo)
>>> print id(t[0]), id(t[1]), id(y)
435264 435264 435264
so you see all the subcopies are the same objects as y (since we reused the memo).
You can read more by checking the Python online documentation:
http://docs.python.org/library/copy.html
The deepcopy() function is recursive, and it will work its way down through a deeply nested object. It uses a dictionary to detect objects it has seen before, to detect an infinite loop. You should just ignore this dictionary.
class A(object):
def __init__(self, *args):
self.lst = args
class B(object):
def __init__(self):
self.x = self
def my_deepcopy(arg):
try:
obj = type(arg)() # get new, empty instance of type arg
for key in arg.__dict__:
obj.__dict__[key] = my_deepcopy(arg.__dict__[key])
return obj
except AttributeError:
return type(arg)(arg) # return new instance of a simple type such as str
a = A(1, 2, 3)
b = B()
b.x is b # evaluates to True
c = my_deepcopy(a) # works fine
c = my_deepcopy(b) # stack overflow, recurses forever
from copy import deepcopy
c = deepcopy(b) # this works because of the second, hidden, dict argument
Just ignore the second, hidden, dict argument. Do not try to use it.
Here's a quick illustration I used for explaining this to myself:
a = [1,2,3]
memo = {}
b = copy.deepcopy(a,memo)
# now memo = {139907464678864: [1, 2, 3], 9357408: 1, 9357440: 2, 9357472: 3, 28258000: [1, 2, 3, [1, 2, 3]]}
key = 139907464678864
print(id(a) == key) #True
print(id(b) == key) #False
print(id(a) == id(memo[key])) #False
print(id(b) == id(memo[key])) #True
in other words:
memo[id_of_initial_object] = copy_of_initial_object