Related
I have two generators, A and B, of unknown length.
I want to know if B is a subsequence (contiguous) of A, so I do the following:
def subseq(A, B):
b0 = next(B)
for a in A:
if a == b0:
break
else: # no-break
# b0 not found in A so B is definitely not a subseq of A
return False
# is the remaining of B a prefix of the remaining of B
return prefix(A, B)
def prefix(A, B):
return all(a == b for a, b in zip(A, B))
However, prefix(A, B) is not exactly correct, as if what remains of A is shorter than what remains of B, then I might get a false positive:
E.g. with A = 'abc' and B = 'abcd' (imagine they are generators), then return all(a == b for a, b in zip(A, B)) would return True.
But if I use zip_longest instead, then I have the complimentary problem -- I would get false negatives:
E.g. with A = 'abcd' and B = 'abc', then return all(a == b for a, b in zip_longest(A, B)) would return False.
What's a sensible way to do this? Specifically, I want to zip to the length of the second argument. I basically want something like zip_(A, B, ziplengthselect=1)
where ziplengthselect=i tells the function that it should zip to the length of the ith argument.
Then the expression all(a == b for a, b in zip_(A, B, fillvalue=sentinel, ziplengthselect=1)) where sentinel is something not found in B, would have the following behavior. If the expression
reaches end of B, then it would evaluate to True
reaches end of A, then it would use the fillvalue, check sentinel == b, fail the check since sentinel was chosen to be something not found in B, and return False
fails an a == b check, then it would evaluate to False
I can think of solutions with try, except blocks, but was wondering if there's a better way.
# Whether generator B is a prefix of generator A.
def prefix(A, B):
for b in B:
try:
a = next(A)
if a != b:
return False
except StopIteration:
# reached end of A
return False
return True
OR
# Whether generator B is a prefix of generator A.
def prefix(A, B):
prefix = all(a == b for a, b in zip(A, B))
if not prefix:
return False
try:
next(B)
# end of B was reached
return True
except StopIteration:
# end of B was not reached
return False
The above code works when A has no duplicates. However if A has duplicates, then we have to tee the generators as follows:
from itertools import tee
def subseq(A, B):
try:
b0 = next(B)
except StopIteration:
return True
while True:
try:
a = next(A)
if a == b0:
A, Acop = tee(A)
B, Bcop = tee(B)
if prefix(Acop, Bcop):
return True
del Acop, Bcop
except StopIteration:
return False
def prefix(A, B):
for b in B:
try:
a = next(A)
if a != b:
return False
except StopIteration:
# reached end of A
return False
return True
# Some tests
A = (i for i in range(10))
B = (i for i in range(5,8))
print(subseq(A, B)) # True
A = (i for i in range(10))
B = (i for i in range(5,11))
print(subseq(A, B)) # False
A = (i for i in [1,2,3]*10 + [1,2,3,4])
B = (i for i in [1,2,3])
print(subseq(A, B)) # True
A = (i for i in [1,1,2,1,1,2]*8 + [3])
B = (i for i in [1,1,2,3])
print(subseq(A, B)) # True
Here's how I solved the analogous subsequence problem for lists. Lists are easier because you can know their length:
def isSublist(lst, sublst):
N, M = len(lst), len(sublst)
starts = (i for i in range(N - M + 1) if lst[i] == sublst[0])
for i in starts:
# i <= N - M so N - i >= M
j = 0
while j < M and lst[i] == sublst[j]:
i += 1
j += 1
if j == M:
return True
return False
I might use deques (although this assumes B is finite):
from collections import deque
from itertools import islice
def subseq(A, B):
B = deque(B)
if not B:
return True
n = len(B)
Asub = deque(islice(A, n-1), n)
for a in A:
Asub.append(a)
if Asub == B:
return True
return False
Might take more or less time/memory than yours. Depends on the input.
Try it online!
A note about yours: For an input like A = iter('a'+'b'*10**7), B = iter('ac') you waste a lot of memory (90 MB on 64-bit Python), since your Acop from the very beginning causes the underlying tee storage to never let go of anything. You'd better do del Acop, Bcop after an unsuccessful prefix check.
It’s possible to build KMP’s partial match table lazily.
from itertools import islice
def has_substring(sup, sub):
sub = LazySequence(sub)
if not sub:
return True
t = kmp_table(sub)
k = 0
for x in sup:
while x != sub[k]:
k = t[k]
if k == -1:
break
if k == -1:
k = 0
continue
k += 1
try:
sub[k]
except IndexError:
return True
return False
class LazySequence:
def __init__(self, iterator):
self.consumed = []
self.iterator = None if iterator is None else iter(iterator)
def __getitem__(self, index):
if index >= len(self.consumed):
self.consumed.extend(islice(self.iterator, index - len(self.consumed) + 1))
return self.consumed[index]
def __iter__(self):
consumed = self.consumed
yield from consumed
for x in self.iterator:
consumed.append(x)
yield x
def __bool__(self):
for _ in self:
return True
return False
def lazy_sequence(g):
def wrap_generator(*args, **kwargs):
ls = LazySequence(None)
ls.iterator = g(ls.consumed, *args, **kwargs)
return ls
return wrap_generator
#lazy_sequence
def kmp_table(t, w):
yield -1
cnd = 0
for x in islice(w, 1, None):
if x == w[cnd]:
yield t[cnd]
else:
yield cnd
while cnd != -1 and x != w[cnd]:
cnd = t[cnd]
cnd += 1
This search is fast (asymptotically optimal time of O(|sub| + |sup|)) and doesn’t use unnecessary time/space when one generator is much longer than the other – including being able to return True when sup is infinite and being able to return False when sub is infinite.
I know how to compose two functions by taking two functions as input and output its composition function but how can I return a composition function f(f(...f(x)))? Thanks
def compose2(f, g):
return lambda x: f(g(x))
def f1(x):
return x * 2
def f2(x):
return x + 1
f1_and_f2 = compose2(f1, f2)
f1_and_f2(1)
You use a loop, inside a nested function:
def compose(f, n):
def fn(x):
for _ in range(n):
x = f(x)
return x
return fn
fn will be have closure that retains references to the f and n that you called compose with.
Note this is mostly just copied from https://stackoverflow.com/a/16739439/2750819 but I wanted to make it clear how you can apply it for any one function n times.
def compose (*functions):
def inner(arg):
for f in reversed(functions):
arg = f(arg)
return arg
return inner
n = 10
def square (x):
return x ** 2
square_n = [square] * n
composed = compose(*square_n)
composed(2)
Output
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
if you want to make it one line composition,
then try this,
def f1(x):
return x * 2
def f2(x):
return x + 1
>>> out = lambda x, f=f1, f2=f2: f1(f2(x)) # a directly passing your input(1) with 2 function as an input (f1, f2) with default so you dont need to pass it as an arguments
>>> out(1)
4
>>>
>>> def compose(f1, n):
... def func(x):
... while n:
... x = f1(x)
... n = n-1
... return x
... return func
>>> d = compose(f1, 2)
>>> d(2)
8
>>> d(1)
4
>>>
you can use functools.reduce:
from functools import reduce
def compose(f1, f2):
return f2(f1)
reduce(compose, [1, f2, f1]) # f1(f2(1))
output:
4
if you want to compose same function n times:
n = 4
reduce(compose, [1, *[f1]*n]) # f1(f1(f1(f1(1))))
output:
16
Regula is a function that finds the minimum value on a set interval (Finds the root of a function).
def Regula(f,Tol,Nmax,a,b):
N = 1
while N < Nmax:
c = (b*f(a)-a*f(b)) / (f(a)-f(b))
if f(c) == 0 or abs(a-b) < Tol:
break
if (np.sign(f(c)) == np.sign(f(a))):
a = c
else:
b =c
N += 1
return c
These are the two functions I am using. M2 calls G2.
def G2(T):
return (48*np.pi**2)/(11*N*(np.log(lam*T+Ts))**2)
def M2(T,func):
return ((N/6)*(func(T))*(T**2))**0.5
M2 works. I promise.
My problem is that I do not know how to generalise Regula to call M2, which calls G2.
Help please!
Min_Mass = Regula (M2(T,G2), Tol, 50, a, b)
a = 1
b = 4
T = np.linspace(a,b,100)
Tol=1e-13
Why don't you simply use:
...
def M2(T,value):
return ((N/6)*( value )*(T**2))**0.5
Min_Mass = Regula (M2(T,G2(T)), Tol, 50, a, b)
...
def multiple(a, b):
"""so I'm trying to return the smallest number n that is a multiple of both a and b.
for example:
multiple(3, 4)
12
multiple(14, 21)
42
"""
def gcd (a,b):
if a < b : a , b = b,a
while b:
a , b = b , a % b
return a
def lcm (a , b):
n= (a*b) / gcd(a,b)
return n
it keeps throwing errors about indentation and logic. I don't understand why. I've tried changing the variables around too.
No need to find GCD, we can directly find LCM. Below code works
def lcmof(x,y):
res=0
mx=max(x,y)
mn=min(x,y)
for i in range(1,mx+1,1):
temp=mx*i
try:
if(temp%mn==0):
res=temp
break
except ZeroDivisionError:
res=0
break
return res
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I've started reading the book Systematic Program Design: From Clarity to Efficiency few days ago. Chapter 4 talks about a systematic method to convert any recursive algorithm into its counterpart iterative. It seems this is a really powerful general method but I'm struggling quite a lot to understand how it works.
After reading a few articles talking about recursion removal using custom stacks, it feels like this proposed method would produce a much more readable, optimized and compact output.
Recursive algorithms in Python where I want to apply the method
#NS: lcs and knap are using implicit variables (i.e.: defined globally), so they won't
#work directly
# n>=0
def fac(n):
if n==0:
return 1
else:
return n*fac(n-1)
# n>=0
def fib(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib(n-1)+fib(n-2)
# k>=0, k<=n
def bin(n,k):
if k==0 or k==n:
return 1
else:
return bin(n-1,k-1)+bin(n-1,k)
# i>=0, j>=0
def lcs(i,j):
if i==0 or j==0:
return 0
elif x[i]==y[j]:
return lcs(i-1,j-1)+1
else:
return max(lcs(i,j-1),lcs(i-1,j))
# i>=0, u>=0, for all i in 0..n-1 w[i]>0
def knap(i,u):
if i==0 or u==0:
return 0
elif w[i]>u:
return knap(i-1,u)
else:
return max(v[i]+knap(i-1,u-w[i]), knap(i-1,u))
# i>=0, n>=0
def ack(i,n):
if i==0:
return n+1
elif n==0:
return ack(i-1,1)
else:
return ack(i-1,ack(i,n-1))
Step Iterate: Determine minimum increments, transform recursion into iteration
The Section 4.2.1 the book talks about determining the appropriate increment:
1) All possible recursive calls
fact(n) => {n-1}
fib(n) => {fib(n-1), fib(n-2)}
bin(n,k) => {bin(n-1,k-1),bin(n-1,k)}
lcs(i,j) => {lcs(i-1,j-1),lcs(i,j-1),lcs(i-1,j)}
knap(i,u) => {knap(i-1,u),knap(i-1,u-w[i])}
ack(i,n) => {ack(i-1,1),ack(i-1,ack(i,n-1)), ack(i,n-1)}
2) Decrement operation
fact(n) => n-1
fib(n) => n-1
bin(n,k) => [n-1,k]
lcs(i,j) => [i-1,j]
knap(i,u) => [i-1,u]
ack(i,n) => [i,n-1]
3) Minimum increment operation
fact(n) => next(n) = n+1
fib(n) => next(n) = n+1
bin(n,k) => next(n,k) = [n+1,k]
lcs(i,j) => next(i,j) = [i+1,j]
knap(i,u) => next(i,u) = [i+1,u]
ack(i,n) => next(i,n) = [i,n+1]
Section 4.2.2 talks about forming the optimized program:
Recursive
---------
def fExtOpt(x):
if base_cond(x) then fExt0(x ) -- Base case
else let rExt := fExtOpt(prev(x)) in -- Recursion
f Ext’(prev(x),rExt) -- Incremental computation
Iterative
---------
def fExtOpt(x):
if base_cond(x): return fExt0(x) -- Base case
x1 := init_arg; rExt := fExt0(x1) -- Initialization
while x1 != x: -- Iteration
x1 := next(x1); rExt := fExt’(prev(x1),rExt) -- Incremental comp
return rExt
How do I create {fibExtOpt,binExtOpt,lcsExtOpt,knapExtOpt,ackExtOpt} in Python?
Additional material about this topic can be found in one of the papers of the main author of the method, Y. Annie Liu, Professor.
So, to restate the question. We have a function f, in our case fac.
def fac(n):
if n==0:
return 1
else:
return n*fac(n-1)
It is implemented recursively. We want to implement a function facOpt that does the same thing but iteratively. fac is written almost in the form we need. Let us rewrite it just a bit:
def fac_(n, r):
return (n+1)*r
def fac(n):
if n==0:
return 1
else:
r = fac(n-1)
return fac_(n-1, r)
This is exactly the recursive definition from section 4.2. Now we need to rewrite it iteratively:
def facOpt(n):
if n==0:
return 1
x = 1
r = 1
while x != n:
x = x + 1
r = fac_(x-1, r)
return r
This is exactly the iterative definition from section 4.2. Note that facOpt does not call itself anywhere. Now, this is neither the most clear nor the most pythonic way of writing down this algorithm -- this is just a way to transform one algorithm to another. We can implement the same algorithm differently, e.g. like that:
def facOpt(n):
r = 1
for x in range(1, n+1):
r *= x
return r
Things get more interesting when we consider more complicated functions. Let us write fibObt where fib is :
def fib(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib(n-1) + fib(n-2)
fib calls itself two times, but the recursive pattern from the book allows only a single call. That is why we need to extend the function to returning not one, but two values. Fully reformated, fib looks like this:
def fibExt_(n, rExt):
return rExt[0] + rExt[1], rExt[0]
def fibExt(n):
if n == 0:
return 0, 0
elif n == 1:
return 1, 0
else:
rExt = fibExt(n-1)
return fibExt_(n-1, rExt)
def fib(n):
return fibExt(n)[0]
You may notice that the first argument to fibExt_ is never used. I just added it to follow the proposed structure exactly.
Now, it is again easy to turn fib into an iterative version:
def fibExtOpt(n):
if n == 0:
return 0, 0
if n == 1:
return 1, 0
x = 2
rExt = 1, 1
while x != n:
x = x + 1
rExt = fibExt_(x-1, rExt)
return rExt
def fibOpt(n):
return fibExtOpt(n)[0]
Again, the new version does not call itself. And again one can streamline it to this, for example:
def fibOpt(n):
if n < 2:
return n
a, b = 1, 1
for i in range(n-2):
a, b = b, a+b
return b
The next function to translate to iterative version is bin:
def bin(n,k):
if k == 0 or k == n:
return 1
else:
return bin(n-1,k-1) + bin(n-1,k)
Now neither x nor r can be just numbers. The index (x) has two components, and the cache (r) has to be even larger. One (not quite so optimal) way would be to return the whole previous row of the Pascal triangle:
def binExt_(r):
return [a + b for a,b in zip([0] + r, r + [0])]
def binExt(n):
if n == 0:
return [1]
else:
r = binExt(n-1)
return binExt_(r)
def bin(n, k):
return binExt(n)[k]
I have't followed the pattern so strictly here and removed several useless variables. It is still possible to translate to an iterative version directly:
def binExtOpt(n):
if n == 0:
return [1]
x = 1
r = [1, 1]
while x != n:
r = binExt_(r)
x += 1
return r
def binOpt(n, k):
return binExtOpt(n)[k]
For completeness, here is an optimized solution that caches only part of the row:
def binExt_(n, k_from, k_to, r):
if k_from == 0 and k_to == n:
return [a + b for a, b in zip([0] + r, r + [0])]
elif k_from == 0:
return [a + b for a, b in zip([0] + r[:-1], r)]
elif k_to == n:
return [a + b for a, b in zip(r, r[1:] + [0])]
else:
return [a + b for a, b in zip(r[:-1], r[1:])]
def binExt(n, k_from, k_to):
if n == 0:
return [1]
else:
r = binExt(n-1, max(0, k_from-1), min(n-1, k_to+1) )
return binExt_(n, k_from, k_to, r)
def bin(n, k):
return binExt(n, k, k)[0]
def binExtOpt(n, k_from, k_to):
if n == 0:
return [1]
ks = [(k_from, k_to)]
for i in range(1,n):
ks.append((max(0, ks[-1][0]-1), min(n-i, ks[-1][1]+1)))
x = 0
r = [1]
while x != n:
x += 1
r = binExt_(x, *ks[n-x], r)
return r
def binOpt(n, k):
return binExtOpt(n, k, k)[0]
In the end, the most difficult task is not switching from recursive to iterative implementation, but to have a recursive implementation that follows the required pattern. So the real question is how to create fibExt', not fibExtOpt.