Is this colidity challenge (Zinc 2018) test case wrong? - python

I just randomly picked up this challenge...
The question and report can be found here: https://app.codility.com/demo/results/training3NRM6P-HSG/
For test case N = 100,000, all performances are different., it says: got 166661666700000 expected 665533373
For N = 100,000 all different performance should not it be: C(100000, 3) = int(len(A) * (len(A) - 1) * (len(A) - 2) / 3 / 2), how is the 665533373 calculated?
Paste my solution here for reading convenience:
def solution(A):
# write your code in Python 3.6
if not A or len(A) < 3:
return 0
if len(set(A)) == len(A):
return int(len(A) * (len(A) - 1) * (len(A) - 2) / 3 / 2)
check = {}
def bt(path, nxt):
if len(path) == 3:
t = tuple(path)
if t not in check:
check[t] = None
return
if len(path) > 3:
return
for i in range(nxt, len(A)):
if i > nxt and A[i] == A[i-1]:
continue
path.append(A[i])
bt(path, i + 1)
path.pop()
bt([], 0)
return len(check)

Look closer at the question! It clearly says that, "since the answer can be very large, provide it modulo 10^9 + 7 (1,000,000,007)".
Your answer, 166661666700000 % (10^9 + 7) = 665533373, which is the expected result.
So all you need to do theoretically is edit the last line of your code like so:
return len(check) % (10**9 + 7)

Related

Why classical division ("/") for large integers is much slower than integer division ("//")?

I ran into a problem: The code was very slow for 512 bit odd integers if you use classical division for (p-1)/2. But with floor division it works instantly. Is it caused by float conversion?
def solovayStrassen(p, iterations):
for i in range(iterations):
a = random.randint(2, p - 1)
if gcd(a, p) > 1:
return False
first = pow(a, int((p - 1) / 2), p)
j = (Jacobian(a, p) + p) % p
if first != j:
return False
return True
The full code
import random
from math import gcd
#Jacobian symbol
def Jacobian(a, n):
if (a == 0):
return 0
ans = 1
if (a < 0):
a = -a
if (n % 4 == 3):
ans = -ans
if (a == 1):
return ans
while (a):
if (a < 0):
a = -a
if (n % 4 == 3):
ans = -ans
while (a % 2 == 0):
a = a // 2
if (n % 8 == 3 or n % 8 == 5):
ans = -ans
a, n = n, a
if (a % 4 == 3 and n % 4 == 3):
ans = -ans
a = a % n
if (a > n // 2):
a = a - n
if (n == 1):
return ans
return 0
def solovayStrassen(p, iterations):
for i in range(iterations):
a = random.randint(2, p - 1)
if gcd(a, p) > 1:
return False
first = pow(a, int((p - 1) / 2), p)
j = (Jacobian(a, p) + p) % p
if first != j:
return False
return True
def findFirstPrime(n, k):
while True:
if solovayStrassen(n,k):
return n
n+=2
a = random.getrandbits(512)
if a%2==0:
a+=1
print(findFirstPrime(a,100))
As noted in comments, int((p - 1) / 2) can produce garbage if p is an integer with more than 53 bits. Only the first 53 bits of p-1 are retained when converting to float for the division.
>>> p = 123456789123456789123456789
>>> (p-1) // 2
61728394561728394561728394
>>> hex(_)
'0x330f7ef971d8cfbe022f8a'
>>> int((p-1) / 2)
61728394561728395668881408
>>> hex(_) # lots of trailing zeroes
'0x330f7ef971d8d000000000'
Of course the theory underlying the primality test relies on using exactly the infinitely precise value of (p-1)/2, not some approximation more-or-less good to only the first 53 most-significant bits.
As also noted in a comment, using garbage is likely to make this part return earlier, not later:
if first != j:
return False
So why is it much slower over all? Because findFirstPrime() has to call solovayStrassen() many more times to find garbage that passes by sheer blind luck.
To see this, change the code to show how often the loop is trying:
def findFirstPrime(n, k):
count = 0
while True:
count += 1
if count % 1000 == 0:
print(f"at count {count:,}")
if solovayStrassen(n,k):
return n, count
n+=2
Then add, e.g.,
random.seed(12)
at the start of the main program so you can get reproducible results.
Using floor (//) division, it runs fairly quickly, displaying
(6170518232878265099306454685234429219657996228748920426206889067017854517343512513954857500421232718472897893847571955479036221948870073830638539006377457, 906)
So it found a probable prime on the 906th try.
But with float (/) division, I never saw it succeed by blind luck:
at count 1,000
at count 2,000
at count 3,000
...
at count 1,000,000
Gave up then - "garbage in, garbage out".
One other thing to note, in passing: the + p in:
j = (Jacobian(a, p) + p) % p
has no effect on the value of j. Right? p % p is 0.

How can i make this factorial function recursive?

A function that calculates (n-1)! , but with steps.
def function1(n, step):
result = 1
for i in range(1, n, step):
result *= i
return result
I'm not allowed to add any more parameters and I need to make it recursive.
I've tried this:
def function2(n, step):
if n < 0:
return 1
return n * function2(n-step, step)
But for let's say:
function2(6,3)
it wouldn't work, the first function will give me 1 * 4
and the second one would give me 6 * 3 * 1
I don't know how to make it work with the step argument.
Edit:
Some more samples:
First function
function1(13, 3) == 280
function1(11, 3) == 280
function1(6, 3) == 4
function1(11, 2) == 945
function1(8, 2) == 105
function1(4, 2) == 3
More sample:
function1(12, 3) == 280
function1(5, 2) == 3
function1(5, 3) == 4
Second function (same values):
function2(13, 3) == 3640
function2(11, 3) == 880
function2(6, 3) == 0
function2(11, 2) == 10395
function2(8, 2) == 0
function2(4, 2) == 0
Edit2: Some more clarifications: The function computes (n-1)!, but with steps. The step argument would just "step over" or "skip" some numbers (e.g.: function1(12, 3) should compute 1*4*7*10, like with the step argument from range(), cause it's used in the first function)
Thank you!
The obvious difference is that you are building range starting at 1 and counting up to n by step, and in the recursive example you are starting at n and counting down by step. This will result in different numbers being multiplied.
Because you are required not to use any additional function parameters, I would suggest an inner helper function, loop -
def fact (n, step):
def loop (m):
if m >= n:
return 1
else:
return m * loop(m + step)
return loop(1)
If you don't want to use a helper function like loop above, you are constrained to complex modulus arithmetic -
def fact (n, step):
if n % step != 1:
return fact(n + 1, step)
elif n < step:
return 1
else:
return (n - step) * fact(n - step, step)
No matter which way you shake it, the modulus operation for this problem is messy -
def fact (n, step):
q = (n - 1) % step
if q:
return fact(n + step - q, step)
elif n < step:
return 1
else:
return (n - step) * fact(n - step, step)
Once academic constraints like "do not use additional parameters" go away, you can multiply the ascending series in a more familiar way -
def fact (n, step, m = 1):
if m >= n:
return 1
else:
return m * fact(n, step, m + step)
All variations of fact above produce identical output -
print(fact(13, 3) == 280) # True
print(fact(11, 3) == 280) # True
print(fact(6, 3) == 4) # True
print(fact(11, 2) == 945) # True
print(fact(8, 2) == 105) # True
print(fact(4, 2) == 3) # True
print(fact(5, 2) == 3) # True
print(fact(5, 3) == 4) # True
Because the steps is calculated beginnig with 1 You have to normalize n to be a multiple of step plus 1 before you begin
And you can cheat the number of arguments by setting the steps negative on recursive calls.
def function2(n, step):
if n <= 1:
return 1
if step > 0:
n = n - 2
n = n - n % step + 1
step = -step
return n * function2(n + step, step)

Is it possible to solve the puzzle using python?

The puzzle
I tried to solve puzzle with the below program.
It is a 4x4 cross math puzzle.
Is there any way to solve quickly
def puzzleTwo (a):
if(a[0] + a[1] - a[2] + a[3] == 19):
#print ("1 equation Success")
if(a[4] - a[5] - a[6] - a[7] == -31):
#print ("2 equation Success")
if(a[8] - a[9] / a[10] + a[11] == 8):
#print ("3 equation Success")
if(a[12] - a[13] / a[14] + a[15] == 1):
#print ("4 equation Success")
if(a[0] + a[4] + a[8] + a[12] == 23):
#print ("5 equation Success")
if(a[1] - a[5] + a[9] - a[13] == -3):
#print ("6 equation Success")
if(a[2] - a[6] / a[10] + a[14] == 5):
#print ("7 equation Success")
if(a[3] + a[7] - a[11] + a[15] == 22):
print (a)
return
from sympy.utilities.iterables import multiset_permutations
import numpy as np
a = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
for p in multiset_permutations(a):
puzzleTwo(p)
The following code uses backtracking algorithm to find a solution in ~3 minutes on Windows 10 PC with i7 CPU 920 # 2.67 MHz
Code
def condition(a):
' Apply conditions individually to allow immediate backtracking when a condition is not met '
if len(a)==4:
return (a[0] + a[1] - a[2] + a[3]) == 19
elif len(a) == 8:
return (a[4] - a[5] - a[6] - a[7]) == -31
elif len(a) == 11:
return (a[6] % a[10]) == 0 and (a[9] % a[10]) == 0
elif len(a)==12:
return (a[8] - a[9] // a[10] + a[11]) == 8
elif len(a) == 13:
return (a[0] + a[4] + a[8] + a[12]) == 23
elif len(a) == 14:
return (a[1] - a[5] + a[9] - a[13]) == -3
elif len(a) == 15:
return (a[2] - a[6] // a[10] + a[14]) == 5 and (a[13] % a[14]) == 0
elif len(a) == 16:
return (a[3] + a[7] - a[11] + a[15]) == 22 and (a[12] - a[13] // a[14] + a[15]) == 1
elif len(a) > 16:
return False # array exceeds max length
else:
return True # not one of the lengths to try conditions
def solve(answer = None):
' Uses backtracking to find solve 4x4 math grid problem '
if answer is None:
answer = ()
if condition(answer):
# satisfies conditions so far
if len(answer) == 16:
# satisfies all conditions
yield answer
else:
# Expand on solution since satisfies conditions so far
for i in range(1, 17):
# Try adding one of the numbers 1 to 17 to current answer
yield from solve(answer + (i,))
from time import time
tstart = time()
print(f'Solution: {next(solve(), None))}') # get first solution
# use list(solve()) to get all solutions
print(f'Elapsed time {time()-tstart}')
Output
Solution: (1, 6, 1, 13, 6, 14, 14, 9, 15, 16, 2, 1, 1, 11, 11, 1)
Elapsed time 189.32917761802673
Explanation
Trying all multiset_permutations of numbers of length 16 is infeasible since there are too many (i.e. 16^16 = 2^64 ~ 18e18).
Idea is to create arrays of increasing size (i.e. 0 to 16 length), but abort early if the array will not satisfy conditions (i.e. backtracking).
To be able to abort early (i.e. backtracking) we:
Split conditions up so we can apply based upon the size of the array (i.e. condition function)
We add the condition that one number will be divisible by another for the division (i.e. if we have x/y then we need x % y == 0)
We use integer division throughout (i.e. x // y)

Alternating counters in Python (Fibonacci Plot)

I've been assigned a project in my computing class to do a report on some area of mathematics in LaTeX, using Python 2.7 code - I chose the Fibonacci sequence.
As part of my project I wanted to include a plot of the Fibonacci 'spiral' which is actually comprised of a series of quarter-circles of increasing radii. As such, I've tried to define a function to give a loop that returns the centres of these quarter-circles so I can create a plot. Using pen and paper I have found the centres of each quarter-circle and noticed that with each new quarter-circle there's an exchange of coordinates - ie. if n is even, the x-coordinate of the previous centre remains the x-coordinate for the nth centre; similarly, when n is odd, the y-coordinate remains the same.
My problem arises with the other coordinate. They work on an alternating pattern of + or - the (n-2)th Fibonacci number to the y-coordinate (for even n) or x-coordinate (for odd) of the previous centre.
I've created the following loop in SageMathCloud, but I think I've deduced that my counters aren't incrementing when I wanted them to:
def centrecoords(n):
k = 0
l = 1
if fib(n) == 1:
return tuple((0,-1))
elif n % 2 == 0 and k % 2 == 0:
return tuple((centrecoords(n-1)[0], centrecoords(n-1)[1] + ((-1) ** k) * fib(n - 2)))
k += 1
elif n % 2 == 0:
return tuple((centrecoords(n-1)[0], centrecoords(n-1)[1] + ((-1) ** k) * fib(n - 2)))
elif n % 2 != 0 and l % 2 == 0:
return tuple((centrecoords(n-1)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1)[1]))
l += 1
else:
return tuple((centrecoords(n-1)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1)[1]))
cen_coords = []
for i in range(0, 21):
cen_coords.append(centrecoords(i))
cen_coords
Any help in making the k counter increment with its if statement only, and the same with the l counter would be greatly appreciated.
Your problem is that k and l are local variables. As such they are lost every time the function exits, and re-start at zero and one respectively when is called again (yes, even when it's called from itself).
Nick's code aims to store a single instance each of k and l in the top-level function, sharing them with the recursive calls.
Another reasonable approach might be to rewrite your recursion as a loop, and yield the sequence. This makes it trivial to keep the state of k and l, as your locals are preserved.
Or, you could re-write your function as a class method, and make k and l instance variables. This behaves similarly, with the instance storing your intermediate state between calls to centrecoords.
Apart from all of these, your code looks like it requires each call to centrecoords to receive the next value of n. So, even if you fix the state problem, this is a poor design.
I'd suggest going the generator route, and taking a single argument, the maximum value of n. Then you can iterate over range(n), yielding each result in turn. Note also that your only recursive call is for n-1, which is just your previous iteration, so you can simply remember it.
Quick demo: I haven't tested this, or checked the corner cases ...
def fib(n):
if n < 2:
return 1
return fib(n-1) + fib(n-2)
def centrecoords(max_n):
# initial values
k = 0
l = 1
result=(0,-1)
# note fib(0) == fib(1) == 1
for n in range(2,max_n):
if n % 2 == 0:
result = (result[0], result[1] + ((-1) ** k) * fib(n - 2))
yield result
if k % 2 == 0:
k += 1
else:
result = (result[0] + ((-1) ** l) * fib(n - 2), result[1])
yield result
if l % 2 == 0:
l += 1
cen_coords = list(centrecoords(21))
Expanding on my comment. Your code could look something like the one below. But please not that you might need to adjust starting values of k and l to -1 and 0 correspondingly, because k and l are incremented before recursion calls (opposite to your code which implied that first a recursion is called and only then k and l are increased).
I also deleted tuple, it is unnecessary in python and hard to read, to create a tuple use comma syntax, e.g.: 1, 2.
Also n == 0 (fib(n) == 0) should be considered as special case, or you program will enter infinite recursion and crash when centrecoords called with n=0.
I have no account on SageMathCloud to test it, but it at least should fix counters increment.
def centrecoords(n, k=0, l=1):
if n == 0:
return 0, 0 # this is pure guess and most likely incorrect, but n == 0 (or fib(n) == 0 should be handled separatly)
if fib(n) == 1:
return 0, -1
elif n % 2 == 0 and k % 2 == 0:
k += 1
return centrecoords(n-1, k, l)[0], centrecoords(n-1, k, l)[1] + ((-1) ** k) * fib(n - 2)
elif n % 2 == 0:
return centrecoords(n-1, k, l)[0], centrecoords(n-1, k, l)[1] + ((-1) ** k) * fib(n - 2)
elif n % 2 != 0 and l % 2 == 0:
l += 1
return centrecoords(n-1, k, l)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1, k, l)[1]
else:
return centrecoords(n-1, k, l)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1, k, l)[1]
cen_coords = []
for i in range(0, 21):
cen_coords.append(centrecoords(i))
cen_coords

How to divide with a loop? (Python)

I am trying to write a function to determine if a number is prime. I have come up with
the following solution, however inelegant, but cannot figure out how to write it.
I want to do the following: take the number x and divide it by every number that is less than itself. If any solution equals zero, print 'Not prime.' If no solution equals zero, print 'Prime.'
In other words, I want the function to do the following:
x % (x - 1) =
x % (x - 2) =
x % (x - 3) =
x % (x - 4) =
etc...
Here is as far as I have been able to get:
def prime_num(x):
p = x - 1
p = p - 1
L = (x % (p))
while p > 0:
return L
Wikipedia provides one possible primality check in Python
def is_prime(n):
if n <= 3:
return n >= 2
if n % 2 == 0 or n % 3 == 0:
return False
for i in range(5, int(n ** 0.5) + 1, 6):
if n % i == 0 or n % (i + 2) == 0:
return False
return True

Categories

Resources