Assignment: Amicably Yours

Jaspreet S. Jheeta 2012EE10457,Group 1

The algorithm to generate amicable pairs uses a function needed for evaluation of sum of proper divisors of a natural number. For eg, consider n=10 , sum of proper divisors of 10= 1+2+5= 8 So the function for evaluation of some of proper divisors of a natural no. is dota(a,b,c,d), where a is the natural number itself , b is what I call a counter which increases by 1 after each call, c is the check which is helpful in termination of algorithm when b=c, d is the storage portion where the value of each divisor is being summed up . Note1: In the following explanation two functions of sml, mod and div are used which indicates the remainder and the quotient respectively . a=bq+r, 0<=r<absolute(b) then a div b=q and a mod b = r Example: 10 div 3= 3 and 10 mod 3=1 [10=3*3+1]
dota(a,b,c,d)= dota(a,b+1,c,d+b+(a div b)) = dota(a,b+1,c,d) = d +b + a div b =d+b =d if b<c and a mod b=0 => b is a divisor of a if b<c and not(a mod b)=0 if b=c and b>c*c and a mod b=0 if b=c and b=c*c and a mod b=0 if b=c and not(a mod b)=0

Now this is our basic function what gives us sum of proper divisors of a is when we substitute b=1,c=[(a)^(0.5)],d=(-a)

Thus a mod 1=0 and so the first stored value will be d+1+a div1 = -a+1+a=1 which satisfies the definition of sum of proper divisors which exclude the number itself from the sum.a(2).i.a(1).d) with above values substituted in dota Now we will deal with function which will actually deal with the pairs .5))=(a)^(0.Correctness of cs(a): (evaluation of sum of proper divisors) Our function is cs(a)=dota(a. gem(n.-a) Note2: 1..i.if b is a divisor of a then a can be expressed as a=b*q where q=a div b .1.j) where n is the number till which we have to evaluate amicable pairs .j) =gem(n.1. .5) and a mod b=0 then (a div b)=a/b>(a/(a)^(0. where [] indicates empty list .[(x)^(1/2)].b.c.cs(i))::j) =j if n>=i>=cs(i) if n>=i and i<cs(i) and not(i=cs(cs(i))) if n>=i and i<cs(i) and (i=cs(cs(i))) if n<i So again we have compressed the function to genAmicable(n)=gem(n..j) =gem(n.e.i+1..So according to the algorithm the storage component will increase by b+(a div b) and this is in accordance with the definition of sum of proper divisor. which implies it is a divisor of a.. i is as usual the counter and j is the list generated for amicable pairs. Basis : for starting case when b=1 and 1 divides every natural number .5) thus if check is kept at less than equal to root(a) then a div b wouldn`t be evaluated thus it is incremented in storage when b is detected.So we define a more compact function cs(a)=dota(a.i+1.i. 2.. if b<(a)^(0.a(m)}  d=(1+a(1)+a(2)+. gem(n.220. Now a/q=b this implies that a mod(a div b)=0 thus a div b is also a divisor...(a/a(1))) assume k+1<c Induction step: For b=k+1 b<c => Case1: if a mod b=0 This implies that b is a divisor of a and a can be expressed as a product of b and q such that q=(a div b). 2.[])..j) =gem(n..+a(m)+(a/a(m))+(a/a(m-1))+.Correctness of Algorithms: 2. Induction Hypothesis: (k>1) Now consider it is correct for b=k and we get divisors {1..i+1.(i.

2. a is a perfect square like 1. We can express a =y*z which implies that a mod z=0 and z<=c<root(a).Case2:if not(a mod b=0) This simply implies that b is not the divisor of a so there should be no increment in the storage component d by mathematical definition which is quite clearly indicated by algorithm and thus the return value is d only.16.9.. Now by saying it is not evaluated doesn’t mean that it was not added.220.thus sum should be incremented by b +a div b Algorithm also returns d+b+(a div b) Case2:a mod b>0 This implies b is not a divisor and simply the function should return d without any increment which is in accordance with the algorithmic response. One will argue that what if a<1 then this algorithm will fail but a check will be imposed using an exception while defining code for genAmicables(n) which will only permit values greater than 0 to this function.e..etc.According to our algorithm z was once checked for divisibility when b=z which we can see was proved correct and hence y was added previously with z as y is in other form a div z. a is not a perfect square According to mathematical definition b is a divisor of a and a div b is also a divisor greater than c as c<root(a). Algorithm under these conditions also return d+b Sub-Case2:if a>c*c i..Correctness of genAmicables(n): genAmicables(n)=gem(n. 4.[]) . If b=c (termination point) Case1:if a mod b=0 Sub-Case1:if a =c*c i. So . Note3: Let us check whether a divisor y of a greater than root(a) is left out of sum or not. According to mathematical definition if b is a divisor of a and a is a perfect square this implies that only b should be incremented in storage d.. we can say that our algorithm for evaluation of sum of proper divisors is correct mathematically .2.e. It is sure by the termination step that the divisibility of y was not checked by our algorithm because it was stopped at b=c<=root(a)<y.

.y(1))] Induction step: Now moving over to b=k+1 gem(k+1..(x(1)...(x(1). [(x(l).....y(l-1)).y(1))]) Subcase2: not(i=cs(cs(i))) then no element would be added in list gem(k+1.(x(2).(x(1).(x(l)..y(l))])= [(x(l)...284)])=[(220.y(l)). [(x(l).284) would be introduced in empty list j and we can see that (220... [(x(l)..(x(1).220.cs(k+1))..y(l))..(x(1)...y(1))]) Case2:i>=cs(i) Then simply return the whole list gem(k+1..220...cs(k+1))..(x(1). sum of proper divisors of 220 is 284 which greater than i and sum of proper divisors of 284 is 220 therefore the a new character (220..y(1))]) Note4: Applying the condition i<cs(i) favours us in two ways first by eliminating repitition and occurrence of perfect numbers.y(1))])= [(x(l).. Secondly.(x(1).y(l-1))...y(l)).(x(l).y(1)).k+1.k+2...(x(l-1)...[(220.y(l)).y(l))..[])=gem(k+1.y(l-1)).y(1))])= [(k+1.y(2))..(x(l-1). [(k+1.y(l1)).e.(x(1).y(l)).(x(1).y(l1)).y(l-1)).(x(l)..y(l))..... [(x(l).(x(l-1)..k+2.(x(l-1). gem(220..k+1.y(1))])= gem(k+1.(x(l-1).y(l))..k+1.(x(1)..y(1))] gem(k......k+1..y(l-1)).221..y(l))....Basis: For n=220...k+2...cs(k+1)) would be added in the list gem(k+1...y(l)).y(l))..(x(l-1).y(1))])= gem(k+1.(x(l-1)..[])=gem(220..(x(l-1).(x(l-1).(x(l-1)......(x(l1)..y(1))])= [(x(l).y(l-1)).284)] as 221>220 Induction Hypothesis: (k>220) Let the algorithm give all amicable pairs for n=k i. if you try evaluating for how many numbers this holds ...220. [(x(l)..(x(1)....(x(1).y(1))])= gem(k+1..y(l-1)).y(l1)).y(l-1))....[])=gem(k.k..(x(l-1)..y(l1))..(x(1).y(1))]) =gem(k+1.k+1... [(x(l). we will get list j= [(x(l)...y(l)).y(l)).284) is an amicable pair. [(x(l).. [(x(1).y(l-1)).y(1))]) Now this will check for i=k+1 Case1:i<cs(i) Sub-Case1:i =cs(cs(i)) then another element (k+1.(x(l-1).

mod and multiplication are bound to take equal time(here we take it unit time) Time complexity for cs(a): Now from i =1 to [ 𝑛] apply one div and one mod operation taking the worst possible case So we can conclude that T(cs(a))=2* 𝑛=O( 𝑛) Time complexity for genAmicables(n): There are two parts in this problem one that it will always evaluate cs(i) for all numbers from 220 to n and for only 25% numbers it will further evaluate cs(cs(i)).1. thus. So we can say that genAmicables(n) contains all the amicable pairs (x. cs(i)<=1+2+.[(x)^(0..Time Complexity: Time complexity would be evaluated taking some assumptions Assumption 1: addition .thus .Proof of termination: 1.220.b`s value by 1 decreasing the value of c-b by 1.[refer to Note 4] Taking the worst case i. The recursion terminates at c=b i..e the set of values of n-i has a lower bound of -1 . subtraction .-a) the function with each call increases the counter . function cs(a) is bound to terminate. The recursion terminates at n-i=-1 i.5)]. will get that cs(cs(i)) is only evaluated in about 25% numbers thus speeding the evaluation process.e. genAmicables(n)=gem(n.[]) the function with each call increases the counter . This fact was basically tested by writing a modified code which would add 1 if i<cs(i) else 0 till i>n..+n1+n=(n(n+1))/2 .e the set of values of c-b has a lower bound 0.true for n=10^(i) .y) such that x<=n 3. function genAmicables(n) is bound to terminate.cs(a)=dota(a.i`s value by 1 decreasing the value of n-i by 1 . 2.logical comparisons and other naive operations take no time. Assumption 2:div . taking form 1 to i-1 all proper divisors of cs(i).

𝟓 / 𝟐)+(n*(n+1))/8 𝟐 =O(𝒏𝟐 ) 5. −𝑎) So due to application of tail recursion by introduction of d what I refered to the storage for sum of proper divisors the space complexity of the function is just proportional to 𝑛0 i.i+1.220. S(gem(n.1.25 𝑐𝑠(𝑛) <=T(genAmicables(n-1))+ 𝑛 + 0. 1.5 / 2 so T(genAmicables(n))= (𝒏𝟏.Space complexity: 1.j))=S(gem(n.c. 𝑛 .[]) Due to application of tail recursion we just get introduction of new elements to the old list to form a new list stored in the function only thus the space complexity is proportional to 1 as the list has always space complexity proportional to 1.d))=S(dota(a.25 (𝑛 ∗ (𝑛 + 1))/2 <=T(genAmicables(n-1))+ 𝑛 + 𝑛/4 2 We can use Cauchy Schwartz formula to evaluate 𝑛 1 𝑛 1 𝑖 𝑖 <=( 𝑛 1 𝑖 ∗(n))^(0.j`))+0 Thus S(genAmicables(a))=O(𝒏𝟎 ) 6.25( 𝑐𝑠(1) + 𝑐𝑠 2 + ⋯ + 𝑐𝑠(𝑛 − 1) + 𝑐𝑠(𝑛)) T(genAmicables(n-1))= 1 + 2 + ⋯ + 𝑛 − 1+0.c.b+1.function cs(a)=dota(a.function genAmicables(n)=gem(n.T(genAmicables(n))= 1 + 2 + ⋯ + 𝑛 − 1 + 𝑛+0. S(dota(a.e.i.Applying Tail Recursion: Both the functions cs(a) and genAmicables(n) are both tail recursive and no further improvement in the algorithms could be done to make any other command tail recursive .b.5)<= 𝑛1.25( 𝑐𝑠 1 + 𝑐𝑠 2 + ⋯ + 𝑐𝑠 𝑛 − 1 ) T(genAmicables(n))=T(genAmicables(n-1))+ 𝑛 + 0.d`))+0 Thus S(cs(a))=O(𝒏𝟎 ) 2.

d) algorithm(i.maxInt) Now the necessary changes in the dota(a.maxInt)-d .For that just put one condition in both b<c and b=c branches of a mod b=0 that if (b+(a div b))>valOf(Int.1.b.e.maxInt)-d then just return 0.d) = 0 else normal algorithm Also raise an exception to remove the possibility of getting n<1 in definition of genAmicables(n) genAmicables(n) = exception invalidnumber = gem(n.b. dota (a. So no further improvement related to reducing space complexity can be introduced.To limit the value of sum o f divisors to upper bound valOf(Int.The tail recursion has been introduced by what I refer to as the storage variable (d and j) which immediately stores the value by applying the operation rather tahn letting it expand after recursive calling and then evaluation of the value of the function.maxInt): Just change the sum of proper divisors algorithm a little bit to ignore those numbers for which the sum of divisors is greater than N where N=valof(Int. the algorithm for sum of proper divisors) will be just checking the condition if new increment will make it overflow or not .c.c.[]) if n<1 if n>=1 if a mod b=0 and b+a div b>valOf(Int. 7.

Sign up to vote on this title
UsefulNot useful