I am trying to implement the divide-and-conquer algorithm for polynomial multiplication. Here is the pseudocode given in the lecture notes:
where A, B are lists of coefficients of each polynomial, n is the size of the problem (degree - 1) and a_l, b_l are indices of the coefficients of interest.
Here is my attempt at implementing it using Python3:
def poly_mult_dc_naive(A, B, n, a, b):
n = int(n)
a = int(a)
b = int(b)
C = [None] * int(2*n - 1)
if n == 1:
C[0] = A[a] * B[b]
return C[0]
C[0:n-1] = poly_mult_dc_naive(A, B, n//2, a, b)
C[n:2*n-1] = poly_mult_dc_naive(A, B, n//2, a + (n // 2), b + (n // 2))
W = poly_mult_dc_naive(A, B, n/2, a, b + (n // 2))
V = poly_mult_dc_naive(A, B, n/2, a + n/2, b)
C[n // 2:n + (n // 2) - 1] += W + V
return C
However I'm getting strange results. For example let A = [1,2,3,4] B = [4,3,2,1] I get:
[4, None, 8, 3, 6, 12, None, 16, 9, 12, 2, None, 4, 1, 2, None, 8, 3, 4, None, None]
Correct answer is [4, 11, 20, 30, 20, 11, 4]
Could someone please point out where I've gone wrong and how it could be done?
Quick update: I think I've managed to debug my code my using a numpy array for C instead of a list. Here is the updated version:
import numpy as np
def poly_mult_dc_naive(A, B, n: int, a: int, b: int):
C = np.zeros(2*n - 1, dtype=int) # here I changed it from list to np array
if n == 1:
C[0] = A[a] * B[b]
return C[0]
C[0:n-1] = poly_mult_dc_naive(A, B, n//2, a, b)
C[n:2*n-1] = poly_mult_dc_naive(A, B, n//2, a + (n // 2), b + (n // 2))
W = poly_mult_dc_naive(A, B, n//2, a, b + (n // 2))
V = poly_mult_dc_naive(A, B, n/2, a + (n//2), b)
C[(n // 2) : (3*n // 2) - 1] += W + V
return C
BONUS QUESTION: Does anyone know of a better way I could keep the arguments n, a, and b as int types?
I just feel like having to write:
n = int(n)
a = int(a)
b = int(b)
might not be the most elegant way.
There should be no need to coerce n,a,b from float to int. Just use // 2 integer division everywhere (i.e. in the W,V lines). That will "keep" ints as ints.
The line C[n // 2:n + (n // 2) - 1] badly needs parenthesizing, it misreads very easily. I'd write C[(n//2) : (3*n//2)-1]
But I seriously recommend you use numpy vectors, not Python lists. Adding, multiplying etc. are vectorized.
Related
still learning Python so any help is welcome.
I have written a funtion to get a fraction, but more often than not the fraction can be simplified. My code does not do this yet. Any ideas how to simplify the fraction without using any import functions?
code:
def add_frac(n1, d1, n2, d2):
frac = (((n1 * d1) + (n2 * d2)), (d1 * d2))
return frac
example:
add_frac(1, 2, 1, 4) gives (6, 8) in stead of (3, 4)
Any help is welcome!
A pretty naive approach to get you started, you can add some checks to make it more efficient.
def simplify_frac(n, d):
i = 2
while i < min(n, d) + 1:
if n % i == 0 and d % i == 0:
n = n // i
d = d // i
else:
i += 1
return n, d
# Some examples
In [105]: simplify_frac(2, 4)
Out[105]: (1, 2)
In [106]: simplify_frac(16, 36)
Out[106]: (4, 9)
In [107]: simplify_frac(7, 3)
Out[107]: (7, 3)
In [108]: simplify_frac(10, 1)
Out[108]: (10, 1)
In [109]: simplify_frac(1, 10)
Out[109]: (1, 10)
In [110]: simplify_frac(102, 10)
Out[110]: (51, 5)
In [111]: simplify_frac(110, 10)
Out[111]: (11, 1)
We use a modulo operator % to check the remainder from integer division by i, if both n and d have a remainder of 0 we know i divides them.
In addition to above answers, if you cannot import any other libraries, here's is the implementation of fractions.gcd for python 2.7 (copied from https://stackoverflow.com/a/11175154/10155740)
>>> print inspect.getsource(gcd)
def gcd(a, b):
"""Calculate the Greatest Common Divisor of a and b.
Unless b==0, the result will have the same sign as b (so that when
b is divided by it, the result comes out positive).
"""
while b:
a, b = b, a%b
return a
so if you'd incorporate this in your code, you should get something like:
def gcd(a, b):
while b:
a, b = b, a%b
return a
def add_frac(n1, d1, n2, d2):
frac = (((n1 * d1) + (n2 * d2)), (d1 * d2))
return tuple(i//gcd(*frac) for i in frac)
print(add_frac(1,2,1,4))
# OUTPUT: (3, 4)
The naive form of adding two fractions returns a correct answer, just not the most reduced correct answer. For that, you need to divide the numerator and denominator of the result by the greatest common denominator (GCD) of the original denominators. In this case, the GCD of 2 and 4 is 2, so dividing 6 and 8 by 2 gives the desired answer (3,4)
math.gcd can be used:
from math import gcd
def add_frac(n1, d1, n2, d2):
x = gcd(d1, d2)
frac = (((n1 * d2) + (n2 * d1)) / x, (d1 * d2) / x)
return frac
though it sounds like you are expected to define your own implementation of gcd.
Here is a solution with a recursive implementation of gcd, using Euclid Algorithm; it also works on negative numbers :
def mygcd(a, b) :
return gcd_rec(abs(a), abs(b))
def gcd_rec(a,b) :
if a*b == 0 : return a+b
if a <= b : return gcd_rec(a, b % a)
return gcd_rec(a % b, b)
def add_frac(n1, d1, n2, d2):
n = n1*d2 + n2*d1
d = d1*d2
g = mygcd(n, d)
return n//g, d//g
You need to divide it by GCD.
import math
def add_frac(n1, d1, n2, d2):
nume = (n1 * d1) + (n2 * d2)
deno = d1 * d2
gcd = math.gcd(nume,deno)
nume /= gcd
deno /= gcd
return (nume,deno)
>>> add_frac(1,2,1,4)
>>> (3.0, 4.0)
I am not sure if it is an issue with my python code or with the latex but it keeps rearranging my equation in the output.
Code:
ddx = '\\frac{{d}}{{dx}}'
f = (a * x ** m) + (b * x ** n) + d
df = sym.diff(f)
df_string = tools.polytex(df)
f_string = tools.polytex(f)
question_stem = f"Find $_\\displaystyle {ddx}\\left({f_string}\\right)$_"
output:
In this case a = 9, b = -4, c = 4, m = (-1/2), n = 3 and I want the output to be in the order of the variable f.
I have tried changing the order to 'lex' and that did not work nor did .expand() or mode = equation
There is an order option for the StrPrinter. If you set the order to 'none' and then pass an unevaluated Add to _print_Add you can get the desired result.
>>> from sympy.abc import a,b,c,x,m,n
>>> from sympy import S
>>> oargs = Tuple(a * x ** m, b * x ** n, c) # in desired order
>>> r = {a: 9, b: -4, c: 4, m: -S.Half, n: 3}
>>> add = Add(*oargs.subs(r).args, evaluate=False) # arg order unchanged
>>> StrPrinter({'order':'none'})._print_Add(add)
9/sqrt(x) - 4*x**3 + 4
Probably this will not be possible in general, as SymPy expressions get reordered with every manipulation, and even with just converting the expression to the internal format.
Here is some code that might work for your specific situation:
from sympy import *
from functools import reduce
a, b, c, m, n, x = symbols("a b c m n x")
f = (a * x ** m) + (b * x ** n) + c
a = 9
b = -4
c = 4
m = -Integer(1)/2
n = 3
repls = ('a', latex(a)), ('+ b', latex(b) if b < 0 else "+"+latex(b)), \
('+ c', latex(c) if c < 0 else "+"+latex(c)), ('m', latex(m)), ('n', latex(n))
f_tex = reduce(lambda a, kv: a.replace(*kv), repls, latex(f))
# only now the values of the variables are filled into f, to be used in further manipulations
f = (a * x ** m) + (b * x ** n) + c
which leaves the following in f_tex:
9 x^{- \frac{1}{2}} -4 x^{3} 4
I have equation of form a+b*n1=c+d*n2, where a,b,c,d are known numbers with around 1000 digits and I need to solve n1.
I tried:
i=1
while True:
a=(a+b)%d
if(a==c):
break
i+=1
print(i)
, but this method is too slow for numbers this big. Is there some better method to use in this kind of situations?
You want to find x such that x = a (mod b) and x = c (mod d). For then, n1 = (x - a) / b and n2 = (x - c) / d.
If b and d are coprime, then the existence of x is guaranteed by the Chinese Remainder Theorem -- and a solution can be found using the Extended Euclidean Algorithm.
If b and d aren't coprime (that is, if gcd(b, d) != 1), then (noting that a = c (mod gcd(b, d))), we can subtract a % gcd(b, d) from both sides, and divide through by gcd(b, d) to reduce to a problem as above.
Putting it into code
Here's code that finds n1 and n2 using this method:
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
return egcd(a, m)[1] % m
def solve(a, b, c, d):
gcd = egcd(b, d)[0]
if gcd != 1:
if a % gcd != c % gcd:
raise ValueError('no solution')
a, c = a - a % gcd, c - c % gcd
a //= gcd
b //= gcd
c //= gcd
d //= gcd
x = a * d * modinv(d, b) + c * b * modinv(b, d)
return (x - a) // b, (x - c) // d
And here's some test code that runs 1000 random trials of 1000-digit inputs:
import sys
sys.setrecursionlimit(10000)
import random
digit = '0123456789'
def rn(k):
return int(''.join(random.choice(digit) for _ in xrange(k)), 10)
k = 1000
for _ in xrange(1000):
a, b, c, d, = rn(k), rn(k), rn(k), rn(k)
print a, b, c, d
try:
n1, n2 = solve(a, b, c, d)
except ValueError, exn:
print 'no solution'
print
continue
if a + b * n1 != c + d * n2:
raise AssertionError('failed!')
print 'found solution:', n1, n2
print
(Note, the recursion limit has to be increased because the egcd function which implements the Extended Euclidean algorithm is recursive, and running it on 1000 digit numbers can require a quite deep stack).
Also note, that this checks the result when a solution is returned. But when a != c (mod gcd(b, d)) and the exception is raised signalling no result, no check is done. So you need to think through if this can fail to find results when solutions do exist.
This runs (1000 trials) in around 7-8 seconds on my machine, so it performs reasonably well.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am learning Python and I want to rewrite this C code.
int rec(int n, int *a , int *b) {
return n == 1 ? *a = *b : rec(n / 2, b, a) + rec((n + 1) / 2, a + n / 2, b + n / 2);
}
int main(void) {
int a[] = { 5, 9, 9, 6, 4, 0 };
int b[] = { 1, 7, 2, 9, 2, 0 };
printf("%d %d", rec(5, a, b), rec(6, b, a));
return 0;
}
To Python:
def rec(n, a, b):
if n == 1:
a=b
return a
else:
return rec(n / 2, b, a) + rec((n + 1) / 2, a + n / 2, b + n / 2)
a = [5, 9, 9, 6, 4, 0];
b = [1, 7, 2, 9, 2, 0];
print(rec(5, a, b))
But it always returns syntax error in a = b statement. What did I do wrong?
Edit: Now, as I fixed code it throws:
File "main.py", line 13, in <module>
print(rec(5,a,b))
File "main.py", line 8, in rec
return rec(n/2,b,a) + rec((n+1)/2,a+n/2,b+n/2)
File "main.py", line 8, in rec
return rec(n/2,b,a) + rec((n+1)/2,a+n/2,b+n/2)
TypeError: can only concatenate list (not "int") to list
If you want to imitate the pointer, you could add another variable i to count your position in the array. Then you can also change the content of your array/list.
def rec(n, a, b, i):
if n == 1:
a[i] = b[i]
return b[i]
else:
return rec(n // 2, b, a, i) + rec((n + 1) // 2, a, b, i + n // 2)
a = [5, 9, 9, 6, 4, 0]
b = [1, 7, 2, 9, 2, 0]
print(rec(5, a, b, 0))
>>> 27
in python you can't use an assignment within the return. Some people talked about this here:
How to assign a variable in IF, and then return it. (Python)
So, just do:
a = b
return a
if you want a boolean answer then it's a==b
otherwise
def rec(n, a, b):
if n == 1:
a=b
return a
It's giving the error because of when you did this else part:
else :
return rec(n / 2, b, a) + rec((n + 1) / 2, a + n / 2, b + n / 2)
Note the second call to rec in the else part, note the arguments, especially the second and third argument. You are actually adding or '+' ing, in this case python thinks you are concatenating as a and b are lists, which is invalid, because n is an integer. So n/2 returns an integer, and a and b being lists,
a + n/2 or b + n/2 does not make sense!!
I need to translate a matlab code to python numpy code
I have 4 2-dimension arrays (A, B, C and D) and want to create a new one "res".
the code in matlab
index1 = find(A == 2 & B > C);
index2 = find(A == 2 & B >= D & B <= C);
res = uint8(zeros(100,100));
res(index1) = 5;
res(index2) = 4;
in Python/numpy I figured out I can create new arrays like this:
res = ((A == 2) & (B > C)) * 5
res = ((A == 2) & (B >= D) & (B <= C)) * 4
but how can I combine this 2 results in only one array? Like the matlab code does.
The translation (in this case) is almost one-for-one:
index1 = ((A == 2) & (B > C))
index2 = ((A == 2) & (B >= D) & (B <= C))
res = np.zeros((100, 100), dtype='uint8')
res[index1] = 5
res[index2] = 4
Alternatively, you could define res as
res = np.where(A == 2, np.where(B > C, 5, np.where(B >= D, 4, 0)), 0)
though I don't think that helps readability :)
PS. As Mr. E suggests, mask1 might be a better variable name than index1 since index (usually) suggests integer values while mask suggest booleans, which is what we have here.