Will the following piece of code be considered as tail recursion? - tail-recursion

Is this below function is a tail recursion? And how to write it more efficiently and clearly.
Based on this question:
We build a table of n rows (1-indexed). We start by writing 0 in the 1st row. Now in every subsequent row, we look at the previous row and replace each occurrence of 0 with 01, and each occurrence of 1 with 10.
For example, for n = 3, the 1st row is 0, the 2nd row is 01, and the 3rd row is 0110.
Given two integer n and k, return the kth (1-indexed) symbol in the nth row of a table of n rows.
def kthGrammar(self, n: int, k: int) -> int:
def getKvalue(k, predecessor):
digit_place = k%2
if predecessor == 0:
return 1 if digit_place == 0 else 0
elif predecessor == 1:
return 0 if digit_place == 0 else 1
def helper(n,k):
if n==1:
return 0
prevK = int((k+1)/2)
return getKvalue(k, helper(n-1,prevK))
return helper(n,k)

Is your function currently tail recursive? No. The recursive call is then followed by a call to getValue.
Your function can be cleaned up dramatically, however. We will begin by replacing 0 and 1 with False and True.
def kthGrammar(n: int, k: int) -> int:
def getKvalue(k : int, predecessor : bool) -> bool:
return (k % 2 == 0) != predecessor
def helper(n : int, k : int) -> bool
if n==1:
return False
prevK = (k+1) // 2
return getKvalue(k, helper(n-1,prevK))
return int(helper(n,k))
Let us further rewrite:
def kthGrammar(n: int, k: int) -> int:
def helper(n : int, k : int) -> bool
if n==1:
return False
prevK = (k+1) // 2
return (k % 2 == 0) != helper(n-1,prevK))
return int(helper(n,k))
Now, we try something rather clever. We define helper2(n : int, k : int, b : bool) = (b != helper(n, k)). How can we implement helper2 recursively?
Clearly, if n = 1, then helper2(n, k, b) = (b != False) = b. Otherwise, we have helper2(n, k, b) = (b != helper(n, k)) = (b != ((k%2 == 0) != helper(n - 1, (k + 1) // 2)) = ((b != (k % 2 == 0)) != helper(n - 1, (k + 1) // 2)) = helper2(n - 1, (k + 1) // 2, b != (k % 2 == 0)).
Note that I used the fact that for Booleans, a != (b != c) is identical to (a != b) != c.
Finally, note that helper(n, k) = (False != helper(n, k) = helper2(n, k, False).
So we define
def kthGrammar(n: int, k: int) -> int:
def helper2(n : int, k : int, b : bool) -> bool
if n==1:
return b
prevK = (k+1) // 2
return helper2(n - 1, prevK, b != (k % 2 == 0))
return int(helper2(n, k, False))
Now, we have a tail recursive function. Tail recursion is just another way to express iteration, so we can easily rewrite this to use a while loop as follows:
def kthGrammar(n : int, k : int) -> int:
b = False
while n != 1:
n, k, b = n - 1, (k + 1) // 2, b != (k % 2 == 0)
return int(b)
Which can again be replaced by
def kthGrammar(n : int, k : int) -> int:
b = False
for _n in range(n, 1, -1):
k, b = (k + 1) // 2, b != (k % 2 == 0)
return int(b)
Of course, there's no reason to start at n and count down to 1. So the final form is
def kthGrammar(n : int, k : int) -> int:
b = False
for _n in range(1, n):
k, b = (k + 1) // 2, b != (k % 2 == 0)
return int(b)
Note that we can actually perform one further optimisation. Once it is the case that k = 1, we see that the line
k, b = (k + 1) // 2, b != (k % 2 == 0)
is a no-op. So the final form is
def kthGrammar(n : int, k : int) -> int:
b = False
for _n in range(1, n):
if k == 1:
break
k, b = (k + 1) // 2, b != (k % 2 == 0)
return int(b)
This will be much more efficient in the case that k <= n - the runtime is O(min(n, log k)) as opposed to O(n).

Related

Looking for simplification of Elliptic curve multiplication calculator

I am looking for a reduced way of this code. I had to do the division separately because of the multiplicative inverse condition.
"""This code calculates the multiplication Elliptic curves over Zp"""
#Initial values for testing
yq = 3
yp = 3
xq = 8
xp = 8
a = 1
p = 11
#Calculate the Euclid greatest common divisor
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return g, x - (b // a) * y, y
#Calculate the multiplicate inverse
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('Mod inverse does not exist')
else:
return x % m
#veces = Number of times for the multiplication
veces = 7
print(f"The next results are the multiplication of {veces}*({xp},{yp})")
z = 1
while z <= (veces - 1):
if xp == xq and yp == yq:
numerador = (3 * pow(xp, 2) + a) % p
denominador = ((2 * yp) % p)
inver = modinv(denominador, p)
landa = (inver * numerador) % p
else:
numerador = (yq - yp) % p
denominador = (xq - xp) % p
inver = modinv(denominador, p)
landa = (inver * numerador) % p
xr = (pow(landa, 2) - xp - xq) % p
yr = (landa * (xp - xr) - yp) % p
z += 1
xp, yp = xr, yr
print(f"The result is ({xp},{yp})")
#Any way to simplify this code? I had to do the division separately but I think we can a reducted code for the division.

How do I compute a^b mod p for very large a, b and p?

So I have to perform the following calculation in python using the following values:
g^response mod p == (commitment)*(public_key_k)^c mod p
response = 1798504909811498641585788989097480059610472466605727419221908325725492625454059229439555828626804680183806468816373215601063565006206068675156743699829546676540107235594790722537029068950539064303645556838303768140715990225949480617994868684304692684872657878847353607016743753387060553449827051212521100889882315213754701194584603400975539123612457745335627513231512419845120373289319998525762252114847939075623683635101459254064343707561020578062272583241711744
g = 633902738424928856783669360417409461352724866437176267937054971987929518113968311572018846775440350331394872441420725806863767569147521628581387346133794141162759618915434384470928048515684966754389921404728037087585951549298706749491681316440418023335644037157549668734734747234193236480208211700649047792505290394509276323498712019417085994608675098219625068478389802372911974790447602798848267203035795626948013815751746314708193865142515067213438779931341448784231764283922931059803394647357407601820746377200693540251395985610151207325893305136968984729108604308872514815118245429658506703427331797397729626291989388778680839647127066755635696870257359738766274560298982571341199340105150191282665463341766016615086716556537263439886148093374656225718217401337340651580107886515914073965138178083420939392671278560530056147682312589783964279302141118430614587577025403023718516789910534505871873011436491653121601912717709648600938567837813521742472036386528727473354399846339619270536399678071529700504925046483796750809603796528358402843506478188359404393987635666119244256746743854126114174948922250715011664059118382465474343042744744366613138372697678748514832068141362891787033831013749278870696574778057534613154041019988
p = 1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085895011648256092372242446818525911665961045150145231572613786749168750228798758833
commitment= 2020675137930448463428712210699816377193388795956936955368481577678186252928308173553464572252495743781550875659773513809435786840535637124578067477896971665575935166527060316619051471051210246502668698327245923852291583447595092128659406887368657131869401939279706099725440871802711550213026404990472910817206252771895691223697718745541630125166110241325111941992598904064238282617139280375363809225737959729994345492410515939174560166672596708090703781989210954
public_key_k= 1003984929417870213515336739925548790770111120760264823891351725159288043410871239949310577373062378763331943177698297734039338641147796251418513873689452683273850688383067446727776769706425799938906550445532369849808734611985822181736172724148838646620601396815561586226959391463589873364266684088955346195425684063242763135652048735053741050269224316588887929259000548116678926935189145525181639366543164685162598318329861171236716093650271474650457781832849534
I have the following function that can perform 2^a mod p where a and p are large:
def fast_powmod(n, m):
pow2 = 2
result = 1
while n > 0:
if n % 2 == 1:
result = (result * pow2) % m
pow2 = (pow2 * pow2) % m
n >>= 1
return result
How do I do the same thing where it's a^b mod p with a and b both being very large?

recursive function: No instance (Num) arising from the literal

I'm trying to make a recursive function which defines division in terms of subtraction. So I have created a new type "DividedResult" to take into account a "divide by zero" case. Do my datatype declaration and function type declaration make sense? I get such errors:
No instance for (Num DividedResult) arising from the literal `0' In the third argument of `go'
Could not deduce (Num DividedResult) arising from a use of `+'
(Probably have to create a Num instance? I have tried, but it doesn't work for me).
Here is my code:
data DividedResult = Result Integer | DividedByZero
dividedBy :: Integer -> Integer -> (DividedResult, Integer)
dividedBy num denom = go num denom 0
where go n d count
| d == 0 = (DividedByZero, n)
| abs n < abs d = (count, n)
| abs n >= abs d && n > 0 && d > 0 = go (n - d) d (count + 1)
| abs n >= abs d && n > 0 && d < 0 = go (n + d) d (count - 1)
| abs n >= abs d && n < 0 && d < 0 = go (n - d) d (count + 1)
| abs n >= abs d && n < 0 && d > 0 = go (n + d) d (count - 1)
The reason you get that error, is because you are trying to return an actual Integer here:
| abs n < abs d = (count, n)
By returning count, an Integer instead of a DividedResult, the compiler thinks you are trying to cast a number into a DividedResult, which is only possible if DividedResult is a Num
In this case, making DividedResult an instance of Num would be overkill; you just need to wrap count:
| abs n < abs d = (Result count, n)

Dafny. Prove that all values from an interval appear in seq

I try to prove the following lemma. It seems really trivial, but I can't manage to prove it. Thank you in advance!
lemma test(x : seq<int>)
// if the values from x are margined by an interval
// the values are different
// and the number of values equals the size of the interval
// then all values from the interval appear in x
requires forall i :: 0 <= i < |x| ==>
0 <= x[i] < |x|;
requires forall i :: 0 <= i < |x| ==>
forall i' :: 0 <= i' < |x| && i != i' ==>
x[i] != x[i'];
ensures forall v :: 0 <= v < |x| ==>
exists i :: 0 <= i < |x| && x[i] == v;
{
}
https://rise4fun.com/Dafny/d8VK
Here's one way to do it, using some facts about set cardinalities.
lemma test(x : seq<int>)
// if the values from x are margined by an interval
// the values are different
// and the number of values equals the size of the interval
// then all values from the interval appear in x
requires forall i :: 0 <= i < |x| ==>
0 <= x[i] < |x|;
requires forall i :: 0 <= i < |x| ==>
forall i' :: 0 <= i' < |x| && i != i' ==>
x[i] != x[i'];
ensures forall v :: 0 <= v < |x| ==> v in x
{
var L: set<int>, R: set<int> := {}, RangeSet(0, |x|);
var i := 0;
CardinalityRangeSet(0, |x|);
while i < |x|
invariant 0 <= i <= |x|
invariant L == set j | 0 <= j < i :: x[j]
invariant forall v | v in L :: v in x
invariant forall v | 0 <= v < |x| :: v in L || v in R
invariant |R| == |x| - i
{
L, R := L + {x[i]}, R - {x[i]};
i := i + 1;
}
}
predicate InRange(lo: int, hi: int, i: int)
{
lo <= i < hi
}
function RangeSet(lo: int, hi: int): set<int>
{
set i | lo <= i < hi && InRange(lo, hi, i)
}
lemma CardinalityRangeSet(lo: int, hi: int)
decreases hi - lo
ensures |RangeSet(lo, hi)| == if lo >= hi then 0 else hi - lo
{
if lo < hi {
assert RangeSet(lo, hi) == {lo} + RangeSet(lo + 1, hi);
CardinalityRangeSet(lo + 1, hi);
}
}
I changed your specification slightly to use the Dafny syntax v in x, which is equivalent to what you wrote, and a little easier for Dafny to reason about.
The basic idea of the proof is to start with the range R of elements 0..|x|, and then iteratively remove elements x[i] from R and add them to L. This maintains the invariant that every number in the range 0..|x| is either in L or R, while the cardinality of R decreases on every iteration. Thus, at the end of the loop R is empty, so every number in the range must be in L, and therefore in x.
I also used one helper lemma proved by induction to show that RangeSet has the expected size.
(Edited to get rid of "No terms found to trigger on" warning in RangeSet. Introducing the predicate InRange gives it something to trigger on, but you still need to include the explicit range in RangeSet because otherwise it can't figure that the set is finite.)

Binomial coefficients - Division by zero error

The "main" code works to calculate every single binomial coefficient, unless (n = k + 1). It is mind boggling - it says there is a division by zero error but I cannot see why. the error occurs in the main function ( d = n2 / c ). Any idea why?
def getInteger( prompt ):
while True:
try:
num = int( input(prompt))
except ValueError:
print( "That is not an integer -- please try again")
continue
return num
def factorial(f):
f = f
q = (f - 1)
fac = (f * q)
while (q) > 1:
q -= 1
fac = (fac * q)
return (fac)
def main():
n = getInteger("enter a factor:")
k = getInteger("enter a factor:")
while n >= k :
n2 = factorial(n)
k2 = factorial(k)
a = n - k
b = factorial(a)
c = b * k2
d = n2 / c
print("n2 = {} k2 = {} a = {} b = {} c = {} d = {}" .format(n2, k2, a, b, c, d) )
return
else:
print("n must be larger than k")
if __name__ == '__main__':
main()
main()
Note that I need to implement the calculations myself so I cannot use libraries.
Your factorial function is not correct for the inputs 0,1. It returns 0 for both of them, while it should return 1 for both of them.

Resources