python generating numbers in modulus - python

i need to iteratively generate number x, which follow these conditions
(x^z) mod n * x < n
n is known, z changes in every cycle
i need it because I'm implementing timing attack on RSA, and it's needed to generate such number to measure time without modular reduction
Thanks.

If the list of z values is not known in advance you could probably try coroutine for this:
def compute_current(x, n, z):
# some computation here
def crunch(x, n):
current = x
z = yield current
while True:
current = compute_current(current, n, z)
z = yield current
c = crunch(x=10)
next(c)
new_x = crunch.send(some_z)
newer_x = crunch.send(some_other_z)
...

Related

This is a random 3-cnf generator, can i make this k-cnf (k literals per clause), I want want to give k as a parameter so i can change it

As you can see this is a function that creates random 3-cnf problems. Given the number of literals and clauses, returns a randomly generated 3-CNF sentence composed of clauses in the form of horn clauses(i used a git library that can transform python code into prolog code). I want this to be k-cnf where i can pass k as a parameter, so if I say k: 3 i get 3-cnf, or k:5 i get 5-cnf. Additionally, i like the numbers to be a character like x1, x2, x2 etc instead of numbers. Is this possible? Thanks in advance :)
def tcnfgen(m, k, horn=1):
cnf = []
def unique(l, k):
t = random.randint(1, k)
while (t in l):
t = random.randint(1, k)
return t
r = (lambda: random.randint(0, 1))
for i in range(m):
x = unique([], k)
y = unique([x], k)
z = unique([x, y], k)
if horn:
cnf.append(Program(P.head(x) <= (P.body(y), P.body(z)))) #horn clauses; head positive, body negative
else:
cnf.append([x, r(), y, r(), z, r()])
return cnf

Let n be a square number. Using Python, how we can efficiently calculate natural numbers y up to a limit l such that n+y^2 is again a square number?

Using Python, I would like to implement a function that takes a natural number n as input and outputs a list of natural numbers [y1, y2, y3, ...] such that n + y1*y1 and n + y2*y2 and n + y3*y3 and so forth is again a square.
What I tried so far is to obtain one y-value using the following function:
def find_square(n:int) -> tuple[int, int]:
if n%2 == 1:
y = (n-1)//2
x = n+y*y
return (y,x)
return None
It works fine, eg. find_square(13689) gives me a correct solution y=6844. It would be great to have an algorithm that yields all possible y-values such as y=44 or y=156.
Simplest slow approach is of course for given N just to iterate all possible Y and check if N + Y^2 is square.
But there is a much faster approach using integer Factorization technique:
Lets notice that to solve equation N + Y^2 = X^2, that is to find all integer pairs (X, Y) for given fixed integer N, we can rewrite this equation to N = X^2 - Y^2 = (X + Y) * (X - Y) which follows from famous school formula of difference of squares.
Now lets rename two factors as A, B i.e. N = (X + Y) * (X - Y) = A * B, which means that X = (A + B) / 2 and Y = (A - B) / 2.
Notice that A and B should be of same odditiy, either both odd or both even, otherwise in last formulas above we can't have whole division by 2.
We will factorize N into all possible pairs of two factors (A, B) of same oddity. For fast factorization in code below I used simple to implement but yet quite fast algorithm Pollard Rho, also two extra algorithms were needed as a helper to Pollard Rho, one is Fermat Primality Test (which allows fast checking if number is probably prime) and second is Trial Division Factorization (which helps Pollard Rho to factor out small factors, which could cause Pollard Rho to fail).
Pollard Rho for composite number has time complexity O(N^(1/4)) which is very fast even for 64-bit numbers. Any faster factorization algorithm can be chosen if needed a bigger space to be searched. My fast algorithm time is dominated by speed of factorization, remaining part of algorithm is blazingly fast, just few iterations of loop with simple formulas.
If your N is a square itself (hence we know its root easily), then Pollard Rho can factor N even much faster, within O(N^(1/8)) time. Even for 128-bit numbers it means very small time, 2^16 operations, and I hope you're solving your task for less than 128 bit numbers.
If you want to process a range of possible N values then fastest way to factorize them is to use techniques similar to Sieve of Erathosthenes, using set of prime numbers, it allows to compute all factors for all N numbers within some range. Using Sieve of Erathosthenes for the case of range of Ns is much faster than factorizing each N with Pollard Rho.
After factoring N into pairs (A, B) we compute (X, Y) based on (A, B) by formulas above. And output resulting Y as a solution of fast algorithm.
Following code as an example is implemented in pure Python. Of course one can use Numba to speed it up, Numba usually gives 30-200 times speedup, for Python it achieves same speed as optimized C++. But I thought that main thing here is to implement fast algorithm, Numba optimizations can be done easily afterwards.
I added time measurement into following code. Although it is pure Python still my fast algorithm achieves 8500x times speedup compared to regular brute force approach for limit of 1 000 000.
You can change limit variable to tweak amount of searched space, or num_tests variable to tweak amount of different tests.
Following code implements both solutions - fast solution find_fast() described above plus very tiny brute force solution find_slow() which is very slow as it scans all possible candidates. This slow solution is only used to compare correctness in tests and compare speedup.
Code below uses nothing except few standard Python library modules, no external modules were used.
Try it online!
def find_slow(N):
import math
def is_square(x):
root = int(math.sqrt(float(x)) + 0.5)
return root * root == x, root
l = []
for y in range(N):
if is_square(N + y ** 2)[0]:
l.append(y)
return l
def find_fast(N):
import itertools, functools
Prod = lambda it: functools.reduce(lambda a, b: a * b, it, 1)
fs = factor(N)
mfs = {}
for e in fs:
mfs[e] = mfs.get(e, 0) + 1
fs = sorted(mfs.items())
del mfs
Ys = set()
for take_a in itertools.product(*[
(range(v + 1) if k != 2 else range(1, v)) for k, v in fs]):
A = Prod([p ** t for (p, _), t in zip(fs, take_a)])
B = N // A
assert A * B == N, (N, A, B, take_a)
if A < B:
continue
X = (A + B) // 2
Y = (A - B) // 2
assert N + Y ** 2 == X ** 2, (N, A, B, X, Y)
Ys.add(Y)
return sorted(Ys)
def trial_div_factor(n, limit = None):
# https://en.wikipedia.org/wiki/Trial_division
fs = []
while n & 1 == 0:
fs.append(2)
n >>= 1
all_checked = False
for d in range(3, (limit or n) + 1, 2):
if d * d > n:
all_checked = True
break
while True:
q, r = divmod(n, d)
if r != 0:
break
fs.append(d)
n = q
if n > 1 and all_checked:
fs.append(n)
n = 1
return fs, n
def fermat_prp(n, trials = 32):
# https://en.wikipedia.org/wiki/Fermat_primality_test
import random
if n <= 16:
return n in (2, 3, 5, 7, 11, 13)
for i in range(trials):
if pow(random.randint(2, n - 2), n - 1, n) != 1:
return False
return True
def pollard_rho_factor(n):
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
import math, random
fs, n = trial_div_factor(n, 1 << 7)
if n <= 1:
return fs
if fermat_prp(n):
return sorted(fs + [n])
for itry in range(8):
failed = False
x = random.randint(2, n - 2)
for cycle in range(1, 1 << 60):
y = x
for i in range(1 << cycle):
x = (x * x + 1) % n
d = math.gcd(x - y, n)
if d == 1:
continue
if d == n:
failed = True
break
return sorted(fs + pollard_rho_factor(d) + pollard_rho_factor(n // d))
if failed:
break
assert False, f'Pollard Rho failed! n = {n}'
def factor(N):
import functools
Prod = lambda it: functools.reduce(lambda a, b: a * b, it, 1)
fs = pollard_rho_factor(N)
assert N == Prod(fs), (N, fs)
return sorted(fs)
def test():
import random, time
limit = 1 << 20
num_tests = 20
t0, t1 = 0, 0
for i in range(num_tests):
if (round(i / num_tests * 1000)) % 100 == 0 or i + 1 >= num_tests:
print(f'test {i}, ', end = '', flush = True)
N = random.randrange(limit)
tb = time.time()
r0 = find_slow(N)
t0 += time.time() - tb
tb = time.time()
r1 = find_fast(N)
t1 += time.time() - tb
assert r0 == r1, (N, r0, r1, t0, t1)
print(f'\nTime slow {t0:.05f} sec, fast {t1:.05f} sec, speedup {round(t0 / max(1e-6, t1))} times')
if __name__ == '__main__':
test()
Output:
test 0, test 2, test 4, test 6, test 8, test 10, test 12, test 14, test 16, test 18, test 19,
Time slow 26.28198 sec, fast 0.00301 sec, speedup 8732 times
For the easiest solution, you can try this:
import math
n=13689 #or we can ask user to input a square number.
for i in range(1,9999):
if math.sqrt(n+i**2).is_integer():
print(i)

numpy precision with large numbers

I want to factorize a large number using Fermat's factorization method. This is how I implemented it:
import numpy as np
def fac(n):
x = np.ceil(np.sqrt(n))
y = x*x - n
while not np.sqrt(y).is_integer():
x += 1
y = x*x - n
return(x + np.sqrt(y), x - np.sqrt(y))
Using this method I want to factor N into its components. Note that N=p*q, where p and q are prime.
I chose the following values to compute N:
p = 34058934059834598495823984675767545695711020949846845989934523432842834738974239847294083409583495898523872347284789757987987387543533846141.0
q = 34058934059834598495823984675767545695711020949846845989934523432842834738974239847294083409583495898523872347284789757987987387543533845933.0
and defined N
N = p*q
Now I factor N:
r = fac(n)
However, the factorization seems to not be correct:
int(r[0])*int(r[1]) == N
It does work for smaller ints:
fac(65537)
Out[1]: (65537.0, 1.0)
I'm quite sure the reason is numerical precision at some point.
I tried calculating N in numpy using object types:
N = np.dot(np.array(p).astype(object), np.array(q).astype(object))
but it doesn't help. Still, the numpy requires a float for the sqrt function.
I also tried using the math library instead of numpy, this library seems to not require a float for its sqrt function, but ultimately running into precision issues as well.
Python int are multiple precision numbers. But numpy is a wrapper around C low level libraries to speed up operations. The downside is that it cannot handle those multi-precision numbers. Worse, if you try to use np.sqrt on them, they will be converted to floating point numbers (C double or numpy float64) what have a precision of about 15 decimal digits.
But as Python int type is already a multiprecision type, you could use math.sqrt to get an approximative value of the true square root, and then use Newton to find a closer value:
def isqrt(n):
x = int(math.sqrt(n))
old = None
while True:
d = (n - x * x) // (2 * x)
if d == 0: break
if d == 1: # infinite loop prevention
if old is None:
old = 1
else: break
x += d
return x
Using it, your fac function could become:
def fac(n):
x = isqrt(n)
if x*x < n: x += 1
y = x * x - n
while True:
z = isqrt(y)
if z*z == y: break
x += 1
y = x*x -n
return x+z, x-z
Demo:
p = 34058934059834598495823984675767545695711020949846845989934523432842834738974239847294083409583495898523872347284789757987987387543533846141
q = 34058934059834598495823984675767545695711020949846845989934523432842834738974239847294083409583495898523872347284789757987987387543533845933
N = p*q
print(fac(N) == (p,q))
prints as expected True

Counting number of ways I can have unique numbers in array

I am trying to find the number of ways to construct an array such that consecutive positions contain different values.
Specifically, I need to construct an array with elements such that each element 1 between and k , all inclusive. I also want the first and last elements of the array to be 1 and x.
Complete problem statement:
Here is what I tried:
def countArray(n, k, x):
# Return the number of ways to fill in the array.
if x > k:
return 0
if x == 1:
return 0
def fact(n):
if n == 0:
return 1
fact_range = n+1
T = [1 for i in range(fact_range)]
for i in range(1,fact_range):
T[i] = i * T[i-1]
return T[fact_range-1]
ways = fact(k) / (fact(n-2)*fact(k-(n-2)))
return int(ways)
In short, I did K(C)N-2 to find the ways. How could I solve this?
It passes one of the base case with inputs as countArray(4,3,2) but fails for 16 other cases.
Let X(n) be the number of ways of constructing an array of length n, starting with 1 and ending in x (and not repeating any numbers). Let Y(n) be the number of ways of constructing an array of length n, starting with 1 and NOT ending in x (and not repeating any numbers).
Then there's these recurrence relations (for n>1)
X(n+1) = Y(n)
Y(n+1) = X(n)*(k-1) + Y(n)*(k-2)
In words: If you want an array of length n+1 ending in x, then you need an array of length n not ending in x. And if you want an array of length n+1 not ending in x, then you can either add any of the k-1 symbols to an array of length n ending in x, or you can take an array of length n not ending in x, and add any of the k-2 symbols that aren't x and don't repeat the last value.
For the base case, n=1, if x is 1 then X(1)=1, Y(1)=0 otherwise, X(1)=0, Y(1)=1
This gives you an O(n)-time method of computing the result.
def ways(n, k, x):
M = 10**9 + 7
wx = (x == 1)
wnx = (x != 1)
for _ in range(n-1):
wx, wnx = wnx, wx * (k-1) + wnx*(k-2)
wnx = wnx % M
return wx
print(ways(100, 5, 2))
In principle you can reduce this to O(log n) by expressing the recurrence relations as a matrix and computing the matrix power (mod M), but it's probably not necessary for the question.
[Additional working]
We have the recurrence relations:
X(n+1) = Y(n)
Y(n+1) = X(n)*(k-1) + Y(n)*(k-2)
Using the first, we can replace the Y(_) in the second with X(_+1) to reduce it down to a single variable. Then:
X(n+2) = X(n)*(k-1) + X(n+1)*(k-2)
Using standard techniques, we can solve this linear recurrence relation exactly.
In the case x!=1, we have:
X(n) = ((k-1)^(n-1) - (-1)^n) / k
And in the case x=1, we have:
X(n) = ((k-1)^(n-1) - (1-k)(-1)^n)/k
We can compute these mod M using Fermat's little theorem because M is prime. So 1/k = k^(M-2) mod M.
Thus we have (with a little bit of optimization) this short program that solves the problem and runs in O(log n) time:
def ways2(n, k, x):
S = -1 if n%2 else 1
return ((pow(k-1, n-1, M) + S) * pow(k, M-2, M) - S*(x==1)) % M
could you try this DP version: (it's passed all tests) (it's inspired by #PaulHankin and take DP approach - will run performance later to see what's diff for big matrix)
def countArray(n, k, x):
# Return the number of ways to fill in the array.
big_mod = 10 ** 9 + 7
dp = [[1], [1]]
if x == 1:
dp = [[1], [0]]
else:
dp = [[1], [1]]
for _ in range(n-2):
dp[0].append(dp[0][-1] * (k - 1) % big_mod)
dp[1].append((dp[0][-1] - dp[1][-1]) % big_mod)
return dp[1][-1]

Finding number of pythagorean triples in a list using python?

I am coding a solution for a problem where the code will find the number of Pythagorean triples in a list given a list a. However, when I submit my code to the auto-grader, there are some test cases where my code fails, but I have no idea what went wrong. Please help me point out my mistake.....
def Q3(a):
lst = [i ** 2 for i in a]
lst.sort()
ans = 0
for x in lst:
for y in lst:
if (x + y) in lst:
ans += 1
return ans // 2
"Pythagorean triples" are integer solutions to the Pythagorean Theorem, for example, 32+42=52. Given a list of positive integers, find the number of Pythagorean triplets. Two Pythagorean triplets are different if at least one integer is different.
Implementation
· Implement a function Q3(A), where the A is a list of positive integers. The size of list A is up to 250.
· There are no duplicates in the list A
· This function returns the number of Pythagorean triplets.
Sample
· Q3( [3,4,6,5] ) = 1
· Q3( [4,5,6] ) = 0
Simple but not very efficient solution would be to loop through the list of numbers in the range (I have taken number from 1 to 100 for instance) in 3 nested for loops as below. But it would be slower as for 100 elements, it needs to have 100^3 operations
triplets = []
for base in range(1,101):
for height in range(1,101):
for hypotenuse in range(1,101):
# check if forms a triplet
if hypotenuse**2 == base**2 + height**2:
triplets.append(base, height, hypotenuse)
This can be made slightly more efficient (there are better solutions)
by calculating hypotenuse for each base and height combination and then check if the hypotenuse is an Integer
triplets = []
for base in range(1,101):
for height in range(1,101):
hypotenuse = math.sqrt(base**2 + height**2)
# check if hypotenuse is integer by ramiander division by 1
if hypotenuse%1==0:
triplets.append(base, height, hypotenuse)
# the above solution written a list comprehension
a = range(1,101)
[(i,j,math.sqrt(i*i+j*j)) for i in a for j in a if math.sqrt(i*i+j*j)%1==0]
If you consider (3,4,5) and (3,5,4) as different, use a set instead of list and get the len(triplets_set) in the end
Problem 1: Suppose your input is
[3,4,5,5,5]
Though it's somewhat unclear in your question, my presumption is that this should count as three Pythogorean triples, each using one of the three 5s.
Your function would only return 1.
Problem 2: As Sayse points out, your "triple" might be trying to use the same number twice.
You would be better off using itertools.combinations to get distinct combinations from your squares list, and counting how many suitable triples appear.
from itertools import combinations
def Q3(a):
squares = [i**2 for i in a]
squares.sort()
ans = 0
for x,y,z in combinations(squares, 3):
if x + y == z:
ans += 1
return ans
Given the constraints of the input you now added to your question with an edit, I don't think there's anything logically wrong with your implementation. The only type of test cases that your code can fail to pass has to be performance-related as you are using one of the slowest solutions by using 3 nested loops iterating over the full range of the list (the in operator itself is implemented with a loop).
Since the list is sorted and we want x < y < z, we should make y start from x + 1 and make z start from y + 1. And since given an x, the value of x depends on the value of y, for each given y we can increment z until z * z < x * x + y * y no longer holds, and if z * z == x * x + y * y at that point, we've found a Pythagorean triple. This allows y and z to sweep through the values above x only once and therefore reduces the time complexity from O(n^3) to O(n^2), making it around 40 times faster when the size of the list is 250:
def Q3(a):
lst = [i * i for i in sorted(a)]
ans = 0
for x in range(len(lst) - 2):
y = x + 1
z = y + 1
while z < len(lst):
while z < len(lst) and lst[z] < lst[x] + lst[y]:
z += 1
if z < len(lst) and lst[z] == lst[x] + lst[y]:
ans += 1
y += 1
return ans

Categories