Best style for maintaining long equation - python

What do you think is the best way of writing this method for calculating an ackermann function value? This function incorporates several 'short cuts' to the simplest method of calculating the value that speeds the calculation up considerably by reducing the amount of recursive calls, but you end up with a long expression.
The versions use:
The line continuation character \
Bracketed nested functions
A single outer set of braces
Does any version seem better to you? why? I'm curious.
>>> def ack4(M, N):
return (N + 1) if M == 0 else \
(N + 2) if M == 1 else \
(2*N + 3) if M == 2 else \
(8*(2**N - 1) + 5) if M == 3 else \
ack4(M-1, 1) if N == 0 else \
ack4(M-1, ack4(M, N-1))
>>> def ack2(M, N):
return (N + 1) if M == 0 else (
(N + 2) if M == 1 else (
(2*N + 3) if M == 2 else (
(8*(2**N - 1) + 5) if M == 3 else (
ack2(M-1, 1) if N == 0 else
ack2(M-1, ack2(M, N-1))))))
>>> def ack3(M, N):
return ((N + 1) if M == 0 else
(N + 2) if M == 1 else
(2*N + 3) if M == 2 else
(8*(2**N - 1) + 5) if M == 3 else
ack3(M-1, 1) if N == 0 else
ack3(M-1, ack3(M, N-1)))
>>> ack2(4, 2) == ack3(4, 2) == ack4(4, 2)
True
>>>

What's wrong with just nesting in a simple elif chain?
def ack5(m, n):
if m == 0:
return (n + 1)
elif m == 1:
return (n + 2)
elif m == 2:
return (2 * n + 3)
elif m == 3:
return (8 * ( 2 ** n - 1) + 5)
elif n == 0:
return ack5(m - 1, 1)
else:
return ack5(m - 1, ack5(m, n - 1))
Python code should be readable for the programmer, so it's more of a personal choice question. If I had to pick one of your 3 examples I'd go with ack4 since those backslashes indicate that everything is one big statement without bloating the expression like a bracket does in my opinion.

Don't be afraid of multiple returns. Also, try to avoid capital letters for local variables.
def ack4(m, n):
if m == 0:
return n + 1
if m == 1:
return n + 2
if m == 2:
return 2 * n + 3
if m == 3:
return (8 * ( 2 ** n - 1) + 5)
if n == 0:
return ack5(m - 1, 1)
return ack5(m - 1, ack5(m, n - 1))

def ack5(m, n):
if m == 0: return n + 1
if m == 1: return n + 2
if m == 2: return 2*n + 3
if m == 3: return 8*(2**n - 1) + 5
if n == 0: return ack5(m-1, 1)
return ack5(m-1, ack5(m, n-1))

Related

improve recursion efficiency in python

def f(n):
if n == 1:
return 1
else:
return (1 / (n - 1)) * (f(n - 1) + (1 / f(n - 1)))
n = int(input())
print(str(round(f(n),2)))
It's been said that my code is not efficient enough since there are two f(n-1)s in the recursion.
How can I improve it ?
If you use python ≥ 3.8 you could use an assignment expression:
def f(n):
if n == 1:
return 1
else:
return (1/(n-1)) * ((F:=f(n-1)) + (1/F)) # (F:=…) gets evaluated as …
# and instantiates F
n = int(input())
print(str(round(f(n),2)))
def f(n):
if n == 1:
return 1
else:
return (1 / (n - 1)) * (f(n - 1) + (1 / f(n - 1)))
n = int(input())
print(str(round(f(n),2)))
#as long as n gets bigger
the function will turn into infinite loop
You can try this:
else:
def alternative(n):
s= (1 / (n - 1))
def altr(s):
return (n - 1) + (1 / (n - 1))

Speeding up perfect swap calculation - avoiding loops

import sys
t=(int(sys.stdin.readline()))
for i in range(0,t):
n=int(sys.stdin.readline())
c=0
s=n*(n+1)/2
if s%2!=0:
print(0)
else:
c=0
i=-1
a=[i for i in range(1,n+1)]
h=s//2
m=0
s1=0
for i in range(n-1,-1,-1):
s1+=a[i]
c+=1
if s1==h:
m=1
break
if s1>h:
break
if m==1:
s1=((c+1)*(2+((c-1)-1)))//2+((n-c-1)*(2+((n-c-1)-1)))//2
print(s1)
else:
print(c)
I am new to python , How can i write this code with using for loop? i don't want to use for loop because i get TLE error. Thanks in advance
Here is the question :
N. Consider the sequence sequence=(1,2,…,N). You should choose two elements of this sequence and swap them.
A swap is perfect if there is an integer o (1≤o<N) such that the sum of the first M elements of the resulting sequence is equal to the sum of its last N−o elements. Find the number of perfect swaps.
i got interested in the problem and found this so far:
a slow version that creates list and really does swap elements is this:
from itertools import combinations
def slow(N):
found = 0
for i, j in combinations(range(N), 2):
lst = list(range(1, N + 1))
lst[i], lst[j] = lst[j], lst[i]
for m in range(1, N):
a = m * (m + 1) // 2
b = (N - m) * (N + m + 1) // 2
if i < m <= j:
a = a - i + j
b = b - j + i
assert a == sum(lst[:m])
assert b == sum(lst[m:])
if sum(lst[:m]) == sum(lst[m:]):
found += 1
if i < m <= j:
assert 2 * m * (m + 1) + 4 * j == N * (N + 1) + 4 * i
else:
assert 2 * m * (m + 1) == N * (N + 1)
else:
if i < m <= j:
assert 2 * m * (m + 1) + 4 * j != N * (N + 1) + 4 * i
else:
assert 2 * m * (m + 1) != N * (N + 1)
return found
as you see i found criteria the indices have to fulfill in order for the sum to be correct:
if i < m <= j:
assert 2 * m * (m + 1) + 4 * j == N * (N + 1) + 4 * i
else:
assert 2 * m * (m + 1) == N * (N + 1)
i also found the direct formula to calculate the sum up to m and the one starting from m:
a = m * (m + 1) // 2
b = (N - m) * (N + m + 1) // 2
if i < m <= j:
a = a - i + j
b = b - j + i
all of that can can be calculated using some basic mathematics.
starting from that you can do some more maths and see that there are 2 cases to consider:
there is an m such that the sum of the original list [1, 2, 3, ..., m, m+1, ..., N] up to m equals the sum of the rest of the list (e.g. N = 20; m = 14). two cases again:
all the swaps that do not cross the m boundary are valid (there are comb(m, 2) + comb((N - m), 2)) of them.
when you split at m-1 you will find more swaps; this time you have to swap accross the m-1 boundary.
the m in that case is calculated from
m = - 1 + sqrt(1 + 2 * N * (N + 1)) / 2
the calculation for m in the first case is not an integer (i.e. 1 + 2 * N * (N + 1) is not a perfect square). the m to consider is then then the floor of the result of the formula above (i use int instead of math.floor). two cases again for the difference of the sum of the two splits:
the difference is even: there are more swaps that need to go over the m boundary.
the difference is odd: no additional swaps (swapping will always result in an even difference)
this is the code:
from math import sqrt, comb
def fast(N):
found = 0
arg = (1 + 2 * N * (N + 1))
sq = round(sqrt(arg))
if sq ** 2 == arg and sq & 1:
m = (-1 + sq) // 2
found += comb(m, 2) + comb((N - m), 2)
m -= 1
found += N - m - 1
else:
m = int((-1 + sqrt(arg)) // 2)
diff = ((m + 1 + N) * (N - m) - m * (m + 1)) // 2
if diff & 1 == 0:
found += N - m
return found

Find how many combinations of integers possible to reach the result

I'm a bit stuck on a python problem.
I'm suppose to write a function that takes a positive integer n and returns the number of different operations that can sum to n (2<n<201) with decreasing and unique elements.
To give an example:
If n = 3 then f(n) = 1 (Because the only possible solution is 2+1).
If n = 5 then f(n) = 2 (because the possible solutions are 4+1 & 3+2).
If n = 10 then f(n) = 9 (Because the possible solutions are (9+1) & (8+2) & (7+3) & (7+2+1) & (6+4) & (6+3+1) & (5+4+1) & (5+3+2) & (4+3+2+1)).
For the code I started like that:
def solution(n):
nb = list(range(1,n))
l = 2
summ = 0
itt = 0
for index in range(len(nb)):
x = nb[-(index+1)]
if x > 3:
for index2 in range(x-1):
y = nb[index2]
#print(str(x) + ' + ' + str(y))
if (x + y) == n:
itt = itt + 1
for index3 in range(y-1):
z = nb[index3]
if (x + y + z) == n:
itt = itt + 1
for index4 in range(z-1):
w = nb[index4]
if (x + y + z + w) == n:
itt = itt + 1
return itt
It works when n is small but when you start to be around n=100, it's super slow and I will need to add more for loop which will worsen the situation...
Do you have an idea on how I could solve this issue? Is there an obvious solution I missed?
This problem is called integer partition into distinct parts. OEIS sequence (values are off by 1 because you don't need n=>n case )
I already have code for partition into k distinct parts, so modified it a bit to calculate number of partitions into any number of parts:
import functools
#functools.lru_cache(20000)
def diffparts(n, k, last):
result = 0
if n == 0 and k == 0:
result = 1
if n == 0 or k == 0:
return result
for i in range(last + 1, n // k + 1):
result += diffparts(n - i, k - 1, i)
return result
def dparts(n):
res = 0
k = 2
while k * (k + 1) <= 2 * n:
res += diffparts(n, k, 0)
k += 1
return res
print(dparts(201))

python programming help for equation

I am new to python and trying to learn some codes. This is my first programming attempt with python. I have a sequence S and a sequence T(which is also a relation of a couples recurrence relationship equation)where
Sn= 2S(n-1)+S(n-2)+4T(n-1)
and T=S(n-1)+T(n-1).
S0=1, S1=2, T0=0 AND T1=1.
How can i write a function that returns nth value of S and T sequence where the function takes n as a parameter and returns Sn,Tn as a tuple as result of calling the function?
Here are the recursive functions:
def T(n):
if n == 0:
return 0
if n == 1:
return 1
return S(n - 1) + T(n - 1)
def S(n):
if n == 0:
return 1
if n == 1:
return 2
return 2 * S(n - 1) + S(n - 2) + 4 * T(n - 1)
def tuple_func(n):
return(S(n), T(n))
Somewhere between n == 20 and n == 30 this becomes ridiculously slow, depending on your threshold for ridiculousness.
"For fun" I've converted the recursive functions to an iterative version. On my computer it can do up to n == 50,000 in about a second.
def tuple_func(n):
S = [1, 2]
T = [0, 1]
if n < 0:
return(None, None)
if 0 >= n < 2:
return(S[n], T[n])
for n in range(2, n + 1):
S.append(2 * S[n - 1] + S[n - 2] + 4 * T[n - 1])
T.append(S[n - 1] + T[n - 1])
return(S[n], T[n])

Longest common substring

I am trying to create a program which will receive two strings and compeer between, and returns the largest common letters in the order they appear.
examples:
string1="a" string2="b"
return ""
string1="abc" string2="ac"
return "ac"
string1:“abcd” string2:“ acdbb”
return:“ abcd"
I need to write 3 codes - "normal way", recursive way and "in memorization" way.
So far I've succeed to code:
def l_c_s(s1, s2):
for i in range(1 + len(s1))]:
mi = [[0] * (1 + len(s2))
long, x_long = 0, 0
for x in range(1, 1 + len(s1)):
for y in range(1, 1 + len(s2)):
if s1[x - 1] == s2[y - 1]:
m[x][y] = m[x - 1][y - 1] + 1
if m[x][y] > long:
long = m[x][y]
x_long = x
m[x][y] = 0
return s1[x_long - long: x_long]
But I don't get what I wanted. just run this code for the string1="abc" string2="ac"
and the see what happens.
Moreover, I have no idea how to make it recursive and neither to write it in memo.
If what you want is really longest common sub-sequence, here is a version using memoization:
s1 = 'abcdd'
s2 = 'add'
mem = [[-1] * len(s2)] * len(s1)
matched = []
def lcs(i,j):
if i < 0 or j < 0:
return 0
if mem[i][j] >= 0:
return mem[i][j]
if s1[i] == s2[j]:
p = 1 + lcs(i-1, j-1)
if p > mem[i][j]:
mem[i][j] = p
matched.append(s1[i])
return max(mem[i][j], lcs(i-1, j), lcs(i, j-1))
lcs_length = lcs(len(s1)-1, len(s2)-1)
lcs = "".join(matched)
print 'LCS: <%s> of length %d' % (lcs, lcs_length)

Categories