faster n choose k for combination of array ruby - ruby

While trying to solve the "paths on a grid" problem, I have written the code
def paths(n, k)
p = (1..n+k).to_a
p.combination(n).to_a.size
end
The code works fine, for instance if n == 8 and k == 2 the code returns 45 which is the correct number of paths.
However the code is very slow when using larger numbers and I'm struggling to figure out how to quicken the process.

Rather than building the array of combinations just to count it, just write the function that defines the number of combinations. I'm sure there are also gems that include this and many other combinatorics functions.
Note that I am using the gem Distribution for the Math.factorial method, but that is another easy one to write. Given that, though, I'd suggest taking #stefan's answer, as it's less overhead.
def n_choose_k(n, k)
Math.factorial(n) / (Math.factorial(k) * Math.factorial(n - k))
end
n_choose_k(10, 8)
# => 45
Note that the n and k here refer to slightly different things than in your method, but I am keeping them as it is highly standard nomenclature in combinatorics for this function.

def combinations(n, k)
return 1 if k == 0 or k == n
(k + 1 .. n).reduce(:*) / (1 .. n - k).reduce(:*)
end
combinations(8, 2) #=> 28
Explanation about the math part
The original equation is
combinations(n, k) = n! / k!(n - k)!
Since n! / k! = (1 * 2 * ... * n) / (1 * 2 * ... * k), for any k <= n there is a (1 * 2 * ... * k) factor both in the numerator and in the denominator, so we can cancel this factor. This makes the equation become
combinations(n, k) = (k + 1) * (k + 2) * ... * (n) / (n - k)!
which is exactly what I did in my Ruby code.

The answers that suggest computing full factorials will generate lots of unnecessary overhead when working with big numbers. You should use the method below for calculating the binomial coefficient: n!/(k!(n-k)!)
def n_choose_k(n, k)
return 0 if k > n
result = 1
1.upto(k) do |d|
result *= n
result /= d
n -= 1
end
result
end
This will perform the minimum operations needed. Note that incrementing d while decrementing n guarantees that there will be no rounding errors. For example, {n, n+1} is guaranteed to have at least one element divisible by two, {n, n+1, n+2} is guaranteed to have at least one element divisible by three and so on.
Your code can be rewritten as:
def paths(x, y)
# Choice of x or y for the second parameter is arbitrary
n_choose_k(x + y, x)
end
puts paths(8, 2) # 45
puts paths(2, 8) # 45
I assume that n and k in the original version were meant to be dimensions so i labeled them x and y instead. There's no need to generate an array here.
Edit: Here is a benchmark script...
require 'distribution'
def puts_time
$stderr.puts 'Completed in %f seconds' % (Time.now - $start_time)
$start_time = Time.now
end
def n_choose_k(n, k)
return 0 if k > n
result = 1
1.upto(k) do |d|
result *= n
result /= d
n -= 1
end
result
end
def n_choose_k_distribution(n, k)
Math.factorial(n) / (Math.factorial(k) * Math.factorial(n - k))
end
def n_choose_k_inject(n, k)
(1..n).inject(:*) / ((1..k).inject(:*) * (1..n-k).inject(:*))
end
def benchmark(&callback)
100.upto(300) do |n|
25.upto(75) do |k|
callback.call(n, k)
end
end
end
$start_time = Time.now
puts 'Distribution gem...'
benchmark { |n, k| n_choose_k_distribution(n, k) }
puts_time
puts 'Inject method...'
benchmark { |n, k| n_choose_k_inject(n, k) }
puts_time
puts 'Answer...'
benchmark { |n, k| n_choose_k(n, k) }
puts_time
Output on my system is:
Distribution gem...
Completed in 1.141804 seconds
Inject method...
Completed in 1.106018 seconds
Answer...
Completed in 0.150989 seconds

Since you're interested in the count rather than the actual combination sets, you should do this with a choose function. The mathematical definition involves evaluating three different factorials, but there's a lot of cancellation going on so you can speed it up by using ranges to avoid the calculations that will be cancelled anyway.
class Integer
def choose(k)
fail 'k > n' if k > self
fail 'args must be positive' if k < 0 or self < 1
return 1 if k == n || k == 0
mm = [self - k, k].minmax
(mm[1]+1..self).reduce(:*) / (2..mm[0]).reduce(:*)
end
end
p 8.choose 6 # => 28
To solve your paths problem, you could then define
def paths(n, k)
(n + k).choose(k)
end
p paths(8, 2) # => 45

The reduce/inject versions are nice. But since speed seemed to be a bit of an issue, I'd suggest the n_choose_k versions from #google-fail.
It is quite insightful and suggests a ~10-fold speed increase.
I would suggest that the iteration use the Lesser of k and ( n - k ).
N-choose-K and N-choose-(N-K) produce the same result (the factors in the denominator are simply reversed). So something like a 52-choose-51 could be done in one iteration.

I usually do the following:
class Integer
def !
(2..self).reduce(1, :*)
end
def choose(k)
self.! / (k.! * (self-k).!)
end
end
Benchmarking:
k = 5
Benchmark.bm do |x|
[10, 100, 1000, 10000, 100000].each do |n|
x.report("#{n}") { n.choose(k) }
end
end
On my machine I get:
user system total real
10 0.000008 0.000001 0.000009 ( 0.000006)
100 0.000027 0.000003 0.000030 ( 0.000031)
1000 0.000798 0.000094 0.000892 ( 0.000893)
10000 0.045911 0.013201 0.059112 ( 0.059260)
100000 4.885310 0.229735 5.115045 ( 5.119902)
Not the fastest thing on the planet, but it's okay for my uses. If it ever becomes a problem, then I can think about optimizing

Related

Generate prime numbers in Ruby (Codewars kata: Primes in numbers)

I have solved a Codewars kata, but I can not submit it because my code takes too long. A lot of people had this problem, but we can not see the solution. The problem is, that generating the prime numbers takes too long (more than 12s) (I generate the primes with a method).
In my computer, I can require the class Prime, and this solves the problem. But in Codewar one can not require the class Prime, therefore, my method of generating prime numbers is too slow.
Any help?
require "pry"
def primeFactors(n)
start_time = Time.now
puts start_time
# find prime numbers smaller than n
nums = (2..(n-1)).to_a
odd_nums = nums.select { |num| num.odd? }
primes = odd_nums.select do |num|
is_prime(num)
end
end_time = Time.now
duration = end_time - start_time
puts end_time
# divide until mod is 1
dividend = n
res_primes = []
while dividend > 1
primes.each do |prime| # prime divisor
new_dividend = dividend.to_f / prime
remainder = dividend % prime
if remainder.zero?
dividend = new_dividend
res_primes << prime
break
end
end
end
freqs = {}
res_primes.each do |res_prime|
freqs[res_prime] = res_primes.count(res_prime)
end
res_string = []
freqs.keys.each do |key|
if freqs[key] == 1
res_string << "(#{key})"
else
res_string << "(#{key}**#{freqs[key]})"
end
end
res_string.join
end
def is_prime(n)
(2..n/2).none?{|i| n % i == 0}
end
Well for starters you really only need to test to Math.sqrt(n).to_i + 1 that should help for larger n values.
This is because if a factor exists where n = a * b then either
If a == b == sqrt(n) # Basically the defn of sqrt
or
If a != b; a < sqrt(n); b > sqrt(n)
If both a and b are less than sqrt(n) then a * b < n
and
If both a and b are greater than sqrt(n) the a * b > n
Secondly, and this is more complex, you only need to test prime numbers to that limit. I could envision a scheme where primes are cached.
Hope this helps.
The more advanced option might look like this:
# Is this number a prime?
module PrimeChecker
#prime_cache = [2,3]
def self.prime?(n)
search_limit = Math.sqrt(n).to_i + 1
last_cache = #prime_cache[-1]
while last_cache < search_limit do
last_cache += 2
#prime_cache << last_cache if PrimeChecker.prime?(last_cache)
end
#prime_cache.each do |pn|
return true if pn > search_limit
return false if (n % pn) == 0
end
true
end
end
# Sample run
#
# 31 mysh>%=PrimeChecker.prime?(1_000_000_000_000)
# false
# Elapsed execution time = 1.592 seconds.
#
This running on an elderly machine with a slow CORE 2 Duo processor.

Ruby Fibonacci algorithm

The following is a method I wrote to calculate a value in the Fibonacci sequence:
def fib(n)
if n == 0
return 0
end
if n == 1
return 1
end
if n >= 2
return fib(n-1) + (fib(n-2))
end
end
It works uptil n = 14, but after that I get a message saying the program is taking too long to respond (I'm using repl.it). Anyone know why this is happening?
Naive fibonacci makes a lot of repeat calculations - in fib(14) fib(4) is calculated many times.
You can add memoization to your algorithm to make it a lot faster:
def fib(n, memo = {})
if n == 0 || n == 1
return n
end
memo[n] ||= fib(n-1, memo) + fib(n-2, memo)
end
fib 14
# => 377
fib 24
# => 46368
fib 124
# => 36726740705505779255899443
As others have pointed out, your implementation's run time grows exponentially in n. There are much cleaner implementations.
Constructive [O(n) run time, O(1) storage]:
def fib(n)
raise "fib not defined for negative numbers" if n < 0
new, old = 1, 0
n.times {new, old = new + old, new}
old
end
Memoized recursion [O(n) run time, O(n) storage]:
def fib_memo(n, memo)
memo[n] ||= fib_memo(n-1, memo) + fib_memo(n-2, memo)
end
def fib(n)
raise "fib not defined for negative numbers" if n < 0
fib_memo(n, [0, 1])
end
Recursive powers of a matrix multiplication using squared halving of the power for when you just gotta know really big factorials like 1_000_000.fib [O(log n) run time and storage (on stack)]:
def matrix_fib(n)
if n == 1
[0,1]
else
f = matrix_fib(n/2)
c = f[0] * f[0] + f[1] * f[1]
d = f[1] * (f[1] + 2 * f[0])
n.even? ? [c,d] : [d,c+d]
end
end
def fib(n)
raise "fib not defined for negative numbers" if n < 0
n.zero? ? n : matrix_fib(n)[1]
end
Your program has exponential runtime due to the recursion you use.
Expanding only the recursive calls a few levels to show you why:
fib(14) = fib(13) + fib(12)
= (fib(12) + fib(11)) + (fib(11) + fib (10))
= (((fib(11) + fib(10)) + (fib(10) + fib(9))) (((fib(10) + fib(9)) + (fib(9) + fib(8)))
= ... //a ton more calls
The terrible runtime might be causing your program to hang, as increasing fib(n) by 1 means you have a TON more recursive calls
your program overflows as Kevin L explained.
instead, you can use an iterative algorithm like this:
def fib (n)
return 0 if n == 0
return 1 if n == 1 or n == 2
x = 0
y = 1
(2..n).each do
z = (x + y)
x = y
y = z
end
return y
end
(0..14).map { |n| fib(n) }
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
I tried comparing the run time of two fibonacci methods on repl.it
require 'benchmark'
def fib_memo(n, memo = {})
if n == 0 || n == 1
return n
end
memo[n] ||= fib_memo(n-1, memo) + fib_memo(n-2, memo)
end
def fib_naive(n)
if n == 0 || n == 1
return n
end
fib_naive(n-1) + fib_naive(n-2)
end
def time(&block)
puts Benchmark.measure(&block)
end
time {fib_memo(14)}
time {fib_naive(14)}
Output
0.000000 0.000000 0.000000 ( 0.000008)
0.000000 0.000000 0.000000 ( 0.000099)
As you can see, the runtime is quite different. As #Uri Agassi suggested, use memoization. The concept is explained quite well here https://stackoverflow.com/a/1988826/5256509

Pascal's Triangle in Ruby

I am writing Pascal's triangle in Ruby, but keep getting the error message:
pascalsTriangle.rb:3:in 'triangle': undefined method `each' for
4:Fixnum (NoMethodError) from pascalsTriangle.rb:18
def triangle(n)
for r in n:
lst=[1]
term=1
k=0
(0..r+1).step(1){ |index|
term=term*(r-k+1)/k
lst.append(term)
k+=1
}
print lst
end
end
triangle(4)
Why code C style in Ruby? :-)
Breaking the problem down would allow you to concentrate on one problem at a time and iterators would make the code more readable. I'm using the binomial theorem to calculate the values in the triangle. If you don't need a super large value from the triangle, this will be fast enough.
Calculating the 1000th line took 2.9 seconds on my virtual linux:
# factorial method
def fact(n)
(1..n).reduce(:*)
end
# binomial theorem, n choose k
def binomial(n,k)
return 1 if n-k <= 0
return 1 if k <= 0
fact(n) / ( fact(k) * fact( n - k ) )
end
def triangle(nth_line)
(0..nth_line).map { |e| binomial(nth_line, e) }
end
p triangle(5)
the final source code:
def triangle(n)
(0..n).each{|r|
lst=[1]
term=1
k=1
(0..r-1).step(1){|index|
term=term*(r-k+1)/k
lst.push term
k+=1
}
p lst
}
end
triangle(4)
changes:
you have syntax error on for r in n:.
a logical error on k=0 that causes Division by zero.
(0..r+1) is changed to (0..r-1)
there is no append method for array. changed to push
p is used instead of print
Factorial(num), takes a number and return the factorial of it.
find_num(n, k), is the mathmatical formula of pascales triangle. !n/
!k * !(n - k) ---- '!' = factorial of number
Lastly pascale(num), this iterates a new row of the triangle by
maping the index numbers or (k) for each row of (n).
If you want to truly understand how this works comment out the
pascale, and simply run numbers through find_num((row number),
(index number)). Then compare to a picture of the triangle to see
the magic for your self
-
def find_num(n, k)
result = factorial(n) / (factorial(k) * factorial(n - k))
end
def pascale(num)
i = 0
scale = 75
while i <= num
new_arr = []
(0..i).map {|x| new_arr << find_num(i, x)}
p new_arr.to_s.rjust(50 + scale)
i += 1
scale += 1
end
def factorial(num)
if num == 0
return 1
else
num *= factorial(num - 1)
end
end
end
pascale(12)

Optimization of code for speed

It's a prime number sieve, but not Eratosthenes's Sieve.
I feel that it's poorly written because I'm new to programming and Ruby in general. This is only the second program I've written in Ruby, but I'd like to optimize it as best as possible. The problem is I don't have a firm understanding of what I need to change to make it faster, except that I know the program path/data structures aren't ideal - I just don't have a concept to work from to MAKE them ideal
An ideal answer won't necessarily say "change X to Y", but it would be more helpful if it pointed me in the direction of a good resource for this kind of information, or a method by which I can derive information regarding efficiency of different pieces of the program.
count = 0
x = 0
$results = Array.new []
inpt = []
class PrimeFun
def initialize(x, y)
array1 = (x..y).to_a
array1.each do |n|
if PrimeFun.primelogic(n%60, n) == 1
array1.delete_if { |p| p % n == 0}
$results << n
elsif n == 2 || n == 3 || n == 5
$results << n
end
end
end
def self.primelogic(r, n)
#prime = case r
when 1, 13, 17, 29, 37, 41, 49, 53
formulaone(n)
when 7, 19, 31, 43
formulatwo(n)
when 11, 23, 47, 59
formulathree(n)
else -1
end
end
def self.formulaone(n)
#x = 1
#y = -1
until 4*(#x**2) >= n
#y = -#y if Math.sqrt(n-(4*(#x**2))).floor - Math.sqrt(n-(4*(#x**2))) == 0
#x += 1
end
#y
end
def self.formulatwo(n)
#x = 1
#y = -1
until 3*(#x**2) >= n
#y = -#y if Math.sqrt(n-(3*(#x**2))).floor - Math.sqrt(n-(3*(#x**2))) == 0
#x += 1
end
#y
end
def self.formulathree(n)
#x = 1
#y = -1
until 3*(#x**2) >= n
#y = -#y if Math.sqrt(((#x**2)+n)/3).floor - Math.sqrt(((#x**2)+n)/3) == 0 && #x > #y
#x += 1
end
#y
end
end
x = STDIN.gets.to_i
while count < x
inpt << STDIN.gets.chomp
count += 1
end
inpt.each do |n|
a = n.split(" ").map { |a| a.to_i }
PrimeFun.new(a[0], a[1])
$results << ""
end
puts $results
You should familiarize yourself with the Benchmark module included in the Ruby standard library to measure the running time of (different versions of) your methods. I have not run the below code suggestions through Benchmark myself, they are just some quick ideas off the top of my head on how to improve the speed and readability of your code - feel free to benchmark them and report back with the results! :-)
Profiling your code to find the bottlenecks is also a good idea - no point spending hours optimizing parts of your code that is not contributing a large amount to the total run time. Check out the ruby-prof gem for a good tool to help you with this.
Now for a quick look at your code and some suggestions for improvement.
Without considering the actual algorithm your are using, your first order of business should be to eliminate your code's tendency to recalculate the same values over and over multiple times.
Also, you seem to be using instance variables (#x, #y, etc.) where local variables will do the job nicely. Not to mention your use of class methods which are only being called from within instance methods of the same class. You should turn those into instance methods as well. (These are not really optimization hints, but suggestions on how to improve your Ruby code.)
Take this method as an example:
def self.formulaone(n)
#x = 1
#y = -1
until 4*(#x**2) >= n
#y = -#y if Math.sqrt(n-(4*(#x**2))).floor - Math.sqrt(n-(4*(#x**2))) == 0
#x += 1
end
#y
end
In the loop, you are calculating the expression 4*(#x**2) three times. One is enough, so store the result in a temporary local variable, fsq. You are also calculating the square root of the same number two times inside the loop. Again, store the value in a temporary variable root, and use that.
def formulaone_b(n)
x = 1
y = -1
until (fsq = 4*(x**2)) >= n
root = Math.sqrt(n - fsq)
y = -y if root.floor - root == 0
x += 1
end
y
end
That should be a good start.
Probably not an optimization, but you can make the code a bit cleaner by calculating the range for x beforehand, then iterate over it using each:
def formulaone_c(n)
y = -1
(1..Math.sqrt(n / 4)).each do |x|
root = Math.sqrt(n - 4*(x**2))
y = -y if root.floor == root # See below
end
y
end
In the above code I have also replaced the comparison root.floor - root == 0 with the simpler but equivalent comparison root.floor == root, removing one unnecessary substraction.
One more idea: instead of calculating n - 4*(x**2) for each iteration, you might just gain a tiny bit of speed by noticing that this value will decrease by x * 8 + 4 every step, so use a helper variable d to update the value of the former expression like this:
def formulaone_d(n)
y = -1
d = n - 4 # Value of n - 4*(x**2) when x = 1
(1..Math.sqrt(n / 4)).each do |x|
root = Math.sqrt(d)
y = -y if root.floor == root
d -= x * 8 + 4 # Value of n - 4*(x**2) after x increases
end
y
end
Correctness
First, your code is not correct:
def self.formulathree(n)
#x = 1
#y = -1
until 3*(#x**2) >= n
#y = -#y if Math.sqrt(((#x**2)+n)/3).floor - Math.sqrt(((#x**2)+n)/3) == 0 && #x > #y
#x += 1
end
#y
end
Whether or not #y is less than #x is immaterial, and it's always true, since #y = ±1 and when #x = 1, #y = -1 < 1.
What you are interested in is the number of representations
n = 3*a^2 - b^2
with integers a > b > 0. Now, a^2 = (n + b^2)/3, so you want
(n + b^2)/3 > b^2
n + b^2 > 3*b^2
n > 2*b^2
and not n > 3*b^2 (b stands for #x here). For example,
143 = 11* 13 = 3*7^2 - 2^2 = 3*8^2 - 7^2
but 3*7^2 = 147 > 143, so #x = 7 wouldn't be considered, so 143 would be deemed prime by formulathree and
179 = 3*9^2 - 8^2
would not be considered prime, although it is, since 3*8^2 = 192 > 179.
Another problem becomes apparent when you output each considered n in initialize for debugging.
array1 = (x..y).to_a
array1.each do |n|
if PrimeFun.primelogic(n%60, n) == 1
array1.delete_if { |p| p % n == 0}
array1.each is more or less
for(index = 0; index < array1.length; ++i)
but when you remove the multiples of n, you also remove n itself, so the element directly after moves to the index n had, and is skipped. You can fix that by deleting only multiples of n greater than n:
array1.delete_if { |p| p > n && p % n == 0 }
Performance
The big performance problem is the algorithm. If you call initialize(2,n), for every prime, you traverse the array and remove multiples by trial division. Each prime is divided by each smaller prime (except 2, 3 and 5) to see whether it shall be removed from the array. That is the infamous Turner "sieve" whose complexity is O((n/log n)^2), almost quadratic. Since you don't even remove multiples of 2,3 and 5 from the array unless these multiples have larger prime factors, the complexity might be even slightly worse.
Micro-optimisations simply aren't worth the effort before you pick a better algorithm.
The next problem is the determination of primality using formulaX. If you also removed multiples of 2, 3 and 5 from the array, the test wouldn't even be necessary, every considered number would be a known prime per trial division. Since you don't, checking the candidate for divisibility by 2, 3 or 5 would be much faster than primelogic.
primelogic uses the logic also used for the Atkin sieve to determine primality, but it tests every number in isolation, therefore testing each number n is O(√n). Computing the square root is far more complicated than a division, hence that takes longer than a prime test by trial division.

Can I reduce the computational complexity of this?

Well, I have this bit of code that is slowing down the program hugely because it is linear complexity but called a lot of times making the program quadratic complexity. If possible I would like to reduce its computational complexity but otherwise I'll just optimize it where I can. So far I have reduced down to:
def table(n):
a = 1
while 2*a <= n:
if (-a*a)%n == 1: return a
a += 1
Anyone see anything I've missed? Thanks!
EDIT: I forgot to mention: n is always a prime number.
EDIT 2: Here is my new improved program (thank's for all the contributions!):
def table(n):
if n == 2: return 1
if n%4 != 1: return
a1 = n-1
for a in range(1, n//2+1):
if (a*a)%n == a1: return a
EDIT 3: And testing it out in its real context it is much faster! Well this question appears solved but there are many useful answers. I should also say that as well as those above optimizations, I have memoized the function using Python dictionaries...
Ignoring the algorithm for a moment (yes, I know, bad idea), the running time of this can be decreased hugely just by switching from while to for.
for a in range(1, n / 2 + 1)
(Hope this doesn't have an off-by-one error. I'm prone to make these.)
Another thing that I would try is to look if the step width can be incremented.
Take a look at http://modular.fas.harvard.edu/ent/ent_py .
The function sqrtmod does the job if you set a = -1 and p = n.
You missed a small point because the running time of your improved algorithm is still in the order of the square root of n. As long you have only small primes n (let's say less than 2^64), that's ok, and you should probably prefer your implementation to a more complex one.
If the prime n becomes bigger, you might have to switch to an algorithm using a little bit of number theory. To my knowledge, your problem can be solved only with a probabilistic algorithm in time log(n)^3. If I remember correctly, assuming the Riemann hypothesis holds (which most people do), one can show that the running time of the following algorithm (in ruby - sorry, I don't know python) is log(log(n))*log(n)^3:
class Integer
# calculate b to the power of e modulo self
def power(b, e)
raise 'power only defined for integer base' unless b.is_a? Integer
raise 'power only defined for integer exponent' unless e.is_a? Integer
raise 'power is implemented only for positive exponent' if e < 0
return 1 if e.zero?
x = power(b, e>>1)
x *= x
(e & 1).zero? ? x % self : (x*b) % self
end
# Fermat test (probabilistic prime number test)
def prime?(b = 2)
raise "base must be at least 2 in prime?" if b < 2
raise "base must be an integer in prime?" unless b.is_a? Integer
power(b, self >> 1) == 1
end
# find square root of -1 modulo prime
def sqrt_of_minus_one
return 1 if self == 2
return false if (self & 3) != 1
raise 'sqrt_of_minus_one works only for primes' unless prime?
# now just try all numbers (each succeeds with probability 1/2)
2.upto(self) do |b|
e = self >> 1
e >>= 1 while (e & 1).zero?
x = power(b, e)
next if [1, self-1].include? x
loop do
y = (x*x) % self
return x if y == self-1
raise 'sqrt_of_minus_one works only for primes' if y == 1
x = y
end
end
end
end
# find a prime
p = loop do
x = rand(1<<512)
next if (x & 3) != 1
break x if x.prime?
end
puts "%x" % p
puts "%x" % p.sqrt_of_minus_one
The slow part is now finding the prime (which takes approx. log(n)^4 integer operation); finding the square root of -1 takes for 512-bit primes still less than a second.
Consider pre-computing the results and storing them in a file. Nowadays many platforms have a huge disk capacity. Then, obtaining the result will be an O(1) operation.
(Building on Adam's answer.)
Look at the Wikipedia page on quadratic reciprocity:
x^2 ≡ −1 (mod p) is solvable if and only if p ≡ 1 (mod 4).
Then you can avoid the search of a root precisely for those odd prime n's that are not congruent with 1 modulo 4:
def table(n):
if n == 2: return 1
if n%4 != 1: return None # or raise exception
...
Based off OP's second edit:
def table(n):
if n == 2: return 1
if n%4 != 1: return
mod = 0
a1 = n - 1
for a in xrange(1, a1, 2):
mod += a
while mod >= n: mod -= n
if mod == a1: return a//2 + 1
It looks like you're trying to find the square root of -1 modulo n. Unfortunately, this is not an easy problem, depending on what values of n are input into your function. Depending on n, there might not even be a solution. See Wikipedia for more information on this problem.
Edit 2: Surprisingly, strength-reducing the squaring reduces the time a lot, at least on my Python2.5 installation. (I'm surprised because I thought interpreter overhead was taking most of the time, and this doesn't reduce the count of operations in the inner loop.) Reduces the time from 0.572s to 0.146s for table(1234577).
def table(n):
n1 = n - 1
square = 0
for delta in xrange(1, n, 2):
square += delta
if n <= square: square -= n
if square == n1: return delta // 2 + 1
strager posted the same idea but I think less tightly coded. Again, jug's answer is best.
Original answer: Another trivial coding tweak on top of Konrad Rudolph's:
def table(n):
n1 = n - 1
for a in xrange(1, n // 2 + 1):
if (a*a) % n == n1: return a
Speeds it up measurably on my laptop. (About 25% for table(1234577).)
Edit: I didn't notice the python3.0 tag; but the main change was hoisting part of the calculation out of the loop, not the use of xrange. (Academic since there's a better algorithm.)
Is it possible for you to cache the results?
When you calculate a large n you are given the results for the lower n's almost for free.
One thing that you are doing is repeating the calculation -a*a over and over again.
Create a table of the values once and then do look up in the main loop.
Also although this probably doesn't apply to you because your function name is table but if you call a function that takes time to calculate you should cache the result in a table and just do a table look up if you call it again with the same value. This save you the time of calculating all of the values when you first run but you don't waste time repeating the calculation more than once.
I went through and fixed the Harvard version to make it work with python 3.
http://modular.fas.harvard.edu/ent/ent_py
I made some slight changes to make the results exactly the same as the OP's function. There are two possible answers and I forced it to return the smaller answer.
import timeit
def table(n):
if n == 2: return 1
if n%4 != 1: return
a1=n-1
def inversemod(a, p):
x, y = xgcd(a, p)
return x%p
def xgcd(a, b):
x_sign = 1
if a < 0: a = -a; x_sign = -1
x = 1; y = 0; r = 0; s = 1
while b != 0:
(c, q) = (a%b, a//b)
(a, b, r, s, x, y) = (b, c, x-q*r, y-q*s, r, s)
return (x*x_sign, y)
def mul(x, y):
return ((x[0]*y[0]+a1*y[1]*x[1])%n,(x[0]*y[1]+x[1]*y[0])%n)
def pow(x, nn):
ans = (1,0)
xpow = x
while nn != 0:
if nn%2 != 0:
ans = mul(ans, xpow)
xpow = mul(xpow, xpow)
nn >>= 1
return ans
for z in range(2,n) :
u, v = pow((1,z), a1//2)
if v != 0:
vinv = inversemod(v, n)
if (vinv*vinv)%n == a1:
vinv %= n
if vinv <= n//2:
return vinv
else:
return n-vinv
tt=0
pri = [ 5,13,17,29,37,41,53,61,73,89,97,1234577,5915587277,3267000013,3628273133,2860486313,5463458053,3367900313 ]
for x in pri:
t=timeit.Timer('q=table('+str(x)+')','from __main__ import table')
tt +=t.timeit(number=100)
print("table(",x,")=",table(x))
print('total time=',tt/100)
This version takes about 3ms to run through the test cases above.
For comparison using the prime number 1234577
OP Edit2 745ms
The accepted answer 522ms
The above function 0.2ms

Resources