karatsuba's integer multiplication algorithm python - python

This code is not passing all the test cases, can somebody help? I only pass the straight forward test then it loses precision.
import math
import unittest
class IntegerMultiplier:
def multiply(self, x, y):
if x < 10 or y < 10:
return x * y
x = str(x)
y = str(y)
m_max = min(len(x), len(y))
x = x.rjust(m_max, '0')
y = y.rjust(m_max, '0')
m = math.floor(m_max / 2)
x_high = int(x[:m])
x_low = int(x[m:])
y_high = int(y[:m])
y_low = int(y[m:])
z1 = self.multiply(x_high, y_high)
z2 = self.multiply(x_low, y_low)
z3 = self.multiply((x_low + x_high), (y_low + y_high))
z4 = z3 - z1 - z2
return z1 * (10 ** m_max) + z4 * (10 ** m) + z2
class TestIntegerMultiplier(unittest.TestCase):
def test_easy_cases(self):
integerMultiplier = IntegerMultiplier()
case2 = integerMultiplier.multiply(2, 2)
self.assertEqual(case2, 4)
case3 = integerMultiplier.multiply(2, 20000)
self.assertEqual(case3, 40000)
case4 = integerMultiplier.multiply(2000, 2000)
self.assertEqual(case4, 4000000)
def test_normal_cases(self):
intergerMultiplier = IntegerMultiplier()
case1 = intergerMultiplier.multiply(1234, 5678)
self.assertEqual(case1, 7006652)
if __name__ == '__main__':
unittest.main()
for the first test case, 'test_easy_cases' all are passing for the other two cases, I get error e.g. AssertionError: 6592652 != 7006652

In choosing m, you choose a base for all following decompositions and compositions. I recommend one with a representation of length about the average of the factors' lengths.
I have "no" idea why time and again implementing Karatsuba multiplication is attempted using operations on decimal digits - there are two places you need to re-inspect:
when splitting a factor f into high and low, low needs to be f mod m, high f // m
in the composition (last expression in IntegerMultiplier.multiply()), you need to stick with m (and 2×m) - using m_max is wrong every time m_max isn't even.

Related

Inefficient algorithm! Can you help me make this more efficient?

In mathematics, a Diophantine equation is a polynomial equation, usually with two or more unknowns, such that only the integer solutions are sought or studied.
This is the equation:
x**2 - 4 * y**2 = n
(where the unknowns are x and y, and n is a given positive number.
My function iterates through every value between 0-n. This is inefficient and can't always hack big n numbers. What is the best way to get the first unknown variable?
def sol_equa(n):
answers = []
for x in range(1 , n+1):
y = ((x ** 2 - n) / 4) ** (1 / 2)
try:
if y == y // 1:
answers.append([x, int(y)])
except TypeError:
continue
if len(answers) >= 1:
answers = list(reversed(answers))
return answers
else:
return []
sol_equation(90005) --> "[[45003, 22501], [9003, 4499], [981, 467], [309, 37]]"
You can use sympy.solvers.diophantine. Take your equation as
from sympy.solvers.diophantine import diophantine
from sympy.abc import x,y
n = 90005
solutions = diophantine(x**2 - 4*y**2 - n)
print(solutions)
#{(-981, 467), (-309, 37), (45003, 22501), (-45003, -22501), (309, -37), (-9003, -4499), (981, 467), (9003, -4499), (-9003, 4499), (45003, -22501), (309, 37), (-309, -37), (-45003, 22501), (9003, 4499), (981, -467), (-981, -467)}
If you want positive solutions only, you can use set comprehension:
positive_solutions = {sol for sol in solutions if sol[0] > 0 and sol[1] > 0}
print(positive_solutions)
#{(981, 467), (9003, 4499), (309, 37), (45003, 22501)}
Execution time tests
from timeit import timeit
sol_equa= '''
def sol_equa(n):
answers = []
for x in range(1 , n+1):
y = ((x ** 2 - n) / 4) ** (1 / 2)
try:
if y == y // 1:
answers.append([x, int(y)])
except TypeError:
continue
if len(answers) >= 1:
answers = list(reversed(answers))
return answers
else:
return []
sol_equa(90005)
'''
sympy_solver = '''
def sympy_solver(n):
solutions = diophantine(x**2 - 4*y**2 - n)
return {sol for sol in solutions if sol[0] > 0 and sol[1] > 0}
sympy_solver(90005)
'''
setup = '''
from sympy.solvers.diophantine import diophantine
from sympy.abc import x,y
'''
print(timeit(sympy_solver,number=1000, setup = setup))
#13.50360608200208
print(timeit(sol_equa,number=1000))
#I don't know, it took too long :P

Implementing a custom datatype in Sympy

I want to perform calculations with a binary operation (Tensor) that takes two non-commutative arguments, converts them into something like a pair, and then does funny things when I multiply these pairs.
# a, b, c, d are non-commutative
Tensor(a, b) * Tensor(c, d) == Tensor(a*c, d*b) # yes, in this order
Furthermore, I want all integer constants to be taken modulo 2.
-Tensor(a, b) == Tensor(a, b)
2*Tensor(a, b) == 0
Tensor(2*a, b) == 0
My shot at doing this:
import sympy as sp
from sympy.core.expr import Expr
class Tensor(Expr):
__slots__ = ['is_commutative']
def __new__(cls, l, r):
l = sp.sympify(l)
r = sp.sympify(r)
obj = Expr.__new__(cls, l, r)
obj.is_commutative = False
return obj
def __neg__(self):
return self
def __mul__(self, other):
if isinstance(other, Tensor):
return Tensor(self.args[0] * other.args[0], other.args[1] * self.args[1])
elif other.is_number:
if other % 2 == 0:
return 0
else:
return self
else:
return sp.Mul(self, other)
x, y = sp.symbols('x, y', commutative=False)
Ym = Tensor(y, 1) - Tensor(1, y)
Yp = Tensor(y, 1) + Tensor(1, y)
Xm = Tensor(x, 1) - Tensor(1, x)
d1 = Ym * Yp + Xm * 0
print(d1)
print(sp.expand(d1))
d2 = Xm * Ym
print(d2)
print(sp.expand(d2))
Output:
(Tensor(1, y) + Tensor(y, 1))**2
Tensor(1, y**2) + 2*Tensor(y, y) + Tensor(y**2, 1)
(Tensor(1, x) + Tensor(x, 1))*(Tensor(1, y) + Tensor(y, 1))
Tensor(1, x)*Tensor(1, y) + Tensor(1, x)*Tensor(y, 1) + Tensor(x, 1)*Tensor(1, y) + Tensor(x, 1)*Tensor(y, 1)
Test #1 is correct.
Test #2 has a term 2*Tensor(y, y) which should be zero (since I'm doing all calculations modulo 2, and, 2 % 2 == 0). How do I enforce that?
Test #3 is correct.
Test #4 does not multiply different Tensors at all. Tensor(1, x)*Tensor(1, y) should be Tensor(1, y*x), for example. How do I enforce that?
Context (if you're interested in why I'm doing this):
This is for calculating a bimodule resolution of an algebra over a char=2 field. A bimodule resolution of an algebra R over a field K is a minimal projective resolution of the same algebra R over its enveloping algebra R⊗R^op. Here op means "multiplication works in the opposite direction". The enveloping algebra has both left and right action on the algebra:
(a⊗b)*r == a*r*b
r*(a⊗b) == b*r*a
There is a theorem that simplifies calculations in the case where a minimal projective resolution of the algebra over the field is known. Still, they are quite tedious and I want to stop doing them manually.

Finding the minimum of a function on a closed interval with Python

Updated: How do I find the minimum of a function on a closed interval [0,3.5] in Python? So far I found the max and min but am unsure how to filter out the minimum from here.
import sympy as sp
x = sp.symbols('x')
f = (x**3 / 3) - (2 * x**2) + (3 * x) + 1
fprime = f.diff(x)
all_solutions = [(xx, f.subs(x, xx)) for xx in sp.solve(fprime, x)]
print (all_solutions)
Since this PR you should be able to do the following:
from sympy.calculus.util import *
f = (x**3 / 3) - (2 * x**2) - 3 * x + 1
ivl = Interval(0,3)
print(minimum(f, x, ivl))
print(maximum(f, x, ivl))
print(stationary_points(f, x, ivl))
Perhaps something like this
from sympy import solveset, symbols, Interval, Min
x = symbols('x')
lower_bound = 0
upper_bound = 3.5
function = (x**3/3) - (2*x**2) - 3*x + 1
zeros = solveset(function, x, domain=Interval(lower_bound, upper_bound))
assert zeros.is_FiniteSet # If there are infinite solutions the next line will hang.
ans = Min(function.subs(x, lower_bound), function.subs(x, upper_bound), *[function.subs(x, i) for i in zeros])
Here's a possible solution using sympy:
import sympy as sp
x = sp.Symbol('x', real=True)
f = (x**3 / 3) - (2 * x**2) - 3 * x + 1
#f = 3 * x**4 - 4 * x**3 - 12 * x**2 + 3
fprime = f.diff(x)
all_solutions = [(xx, f.subs(x, xx)) for xx in sp.solve(fprime, x)]
interval = [0, 3.5]
interval_solutions = filter(
lambda x: x[0] >= interval[0] and x[0] <= interval[1], all_solutions)
print(all_solutions)
print(interval_solutions)
all_solutions is giving you all points where the first derivative is zero, interval_solutions is constraining those solutions to a closed interval. This should give you some good clues to find minimums and maximums :-)
The f.subs commands show two ways of displaying the value of the given function at x=3.5, the first as a rational approximation, the second as the exact fraction.

Trying to implement Newton's Method in order to find root. Not working, but why?

I'm trying to use Newton's Method in order to find a root of an example function, but it doesn't work. Help? (Python) The values printed seem right-ish at first, then get out of hand.
class Newton_Method():
#Use Newton's Method in order to find the nth approximation of the root of f(x).
#Given:
# f(x) = 48x(1+x)^60 - (1+x)^60 + 1
# f'(x) = 12(1+x)^59(244x-1)
# x1 = 0.0076
# x2 = x1 - (f(x1)/f'(x1))
x1 = 0.0076
x2 = None
f = 48*x1*(1+x1)**60 - (1+x1)**60 + 1
df = 12*(1+x1)**59*(244*x1-1)
n = int(raw_input('Enter the number of times to approximate the root: '))
for i in range(n):
x2 = x1 - (f/df)
print x2 #I print to check, but the values are all jacked up. :/
x1 = x2
print x1
I don't know about your equations, but the python syntax is like this:
def f(x):
return 48 * x * (1 + x) ** 60 - (1 + x) ** 60 + 1
def df(x):
return 12 * (1 + x) ** 59 * (244 * x - 1)
n = int(raw_input('Enter the number of times to approximate the root: '))
x = 0.0076
for i in range(n):
x = x - f(x) / df(x)
print x

Karatsuba algorithm incorrect result

I just simply followed the pseudo code on wiki http://en.wikipedia.org/wiki/Karatsuba_algorithm
But the result of this implementation is very unstable.
It works sometimes but in case like 100*100. It does fail. What I missed here? please take a look.
from math import *
f = lambda x: (int(x) & 1 and True) and 1
def fast_multiply( x = "100", y = "100"):
print "input "+x+" | "+y
int_buff = map( int, [x, y])
if int_buff[0] < 10 or int_buff[1] < 10:
#print "lol"
return int_buff[0]*int_buff[1]
degree = max( x.__len__(), y.__len__())
higher_x, lower_x = x[ : int( ceil( len(x) / 2.0))], x[ len(x)/2 +f(len(x)):]
higher_y, lower_y = y[ : int( ceil( len(y) / 2.0))], y[ len(y)/2 +f(len(y)):]
#print lower_x+" & "+lower_y
z0 = fast_multiply(lower_x, lower_y) #z0 = 0
z1 = fast_multiply(str(int(lower_x)+int(higher_x)), str(int(lower_y)+int(higher_y)))
z2 = fast_multiply(higher_x, higher_y)
print "debug "+str(z0)+" "+str(z1)+" "+str(z2)
return z2*(10**degree) + (z1-z2-z0)*(10**(degree/2))+z0
if __name__ == '__main__':
print fast_multiply()
I have noticed in the case 100*100 z2 will be 100 which is correct. This gives z2*(10**3)=100000 which is definitely wrong...
The pseudocode you used was wrong. The problem was in z2*(10**degree). You should have raised the base to 2*m where m is what you meant to calculate with int( ceil(len(x) / 2.0)) (len(x) and len(y) should both have been degree).
I couldn't resist refactoring it... a little. I used the names from the definitions on the wiki. It would be straightforward to implement it with an arbitrary base, but I stuck with 10 for simplicity.
def kmult(x, y):
if min(x, y) < 10:
return x * y
m = half_ceil(degree(max(x, y)))
x1, x0 = decompose(x, m)
y1, y0 = decompose(y, m)
z2 = kmult(x1, y1)
z0 = kmult(x0, y0)
z1 = kmult(x1 + x0, y1 + y0) - z2 - z0
xy = z2 * 10**(2*m) + z1 * 10**m + z0
return xy
def decompose(x, m):
return x // 10 ** m, x % 10 ** m
def degree(x):
return len(str(x))
def half_ceil(n):
return n // 2 + (n & 1)
Testing:
print kmult(100, 100)
def test_kmult(r):
for x, y in [(a, b) for b in range(r+1) for a in range(r+1)]:
if kmult(x, y) != x * y:
print('fail')
break
else:
print('success')
test_kmult(100)
Result:
10000
success

Categories

Resources