I have some simple Mathematica code that I'm struggling to convert to Python and could use some help:
a = ((-1)^(n))*4/(Pi*(2 n + 1));
f = a*Cos[(2 n + 1)*t];
sum = Sum[f, {n, 0, 10}];
Plot[sum, {t, -2 \[Pi], 2 \[Pi]}]
The plot looks like this:
For context, I have a function f(t):
I need to plot the sum of the first 10 terms. In Mathematica this was pretty straighforward, but for some reason I just can't seem to figure out how to make it work in Python. I've tried defining a function a(n), but when I try to set f(t) equal to the sum using my list of odd numbers, it doesn't work because t is not defined, but t is a variable. Any help would be much appreciated.
Below is a sample of one of the many different things I've tried. I know that it's not quite right in terms of getting the parity of the terms to alternate, but more important I just want to figure out how to get 'f' to be the sum of the first 10 terms of the summation:
n = list(range(1,20,2))
def a(n):
return ((-1)**(n))*4/(np.pi*n)
f = 0
for i in n:
f += a(i)*np.cos(i*t)
modifying your code, look the part which are different, mostly the mistake was in the part which you are not calculating based on n 0-10 :
n = np.arange(0,10)
t = np.linspace(-2 * np.pi, 2 *np.pi, 10000)
def a(n):
return ((-1)**(n))*4/(np.pi*(2*n+1))
f = 0
for i in n:
f += a(i)*np.cos((2*i +1) * t)
however you could write you could in matrix form, and avoid looping, using the vector and broadcasting:
n = np.arange(10)[:,None]
t = np.linspace(-2 * np.pi, 2 *np.pi, 10000)[:,None]
a = ((-1) ** n) * 4 / (np.pi*(2*n + 1))
f = (a * np.cos((2 * n + 1) * t.T )).sum(axis=0)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm a beginner in programming and I'm looking for a nice idea how to generate three integers that satisfy a condition.
Example:
We are given n = 30, and we've been asked to generate three integers a, b and c, so that 7*a + 5*b + 3*c = n.
I tried to use for loops, but it takes too much time and I have a maximum testing time of 1000 ms.
I'm using Python 3.
My attempt:
x = int(input())
c = []
k = []
w = []
for i in range(x):
for j in range(x):
for h in range(x):
if 7*i + 5*j + 3*h = x:
c.append(i)
k.append(j)
w.append(h)
if len(c) == len(k) == len(w)
print(-1)
else:
print(str(k[0]) + ' ' + str(c[0]) + ' ' + str(w[0]))
First, let me note that your task is underspecified in at least two respects:
The allowed range of the generated values is not specified. In particular, you don't specify whether the results may include negative integers.
The desired distribution of the generated values is not specified.
Normally, if not specified, one might assume that a uniform distribution on the set of possible solutions to the equation was expected (since it is, in a certain sense, the most random possible distribution on a given set). But a (discrete) uniform distribution is only possible if the solution set is finite, which it won't be if the range of results is unrestricted. (In particular, if (a, b, c) is a solution, then so is (a, b + 3k, c − 5k) for any integer k.) So if we interpret the task as asking for a uniform distribution with unlimited range, it's actually impossible!
On the other hand, if we're allowed to choose any distribution and range, the task becomes trivial: just make the generator always return a = −n, b = n, c = n. Clearly this is a solution to the equation (since −7n + 5n + 3n = (−7 + 5 + 3)n = 1n), and a degenerate distribution that assigns all probability mass to single point is still a valid probability distribution!
If you wanted a slightly less degenerate solution, you could pick a random integer k (using any distribution of your choice) and return a = −n, b = n + 3k, c = n − 5k. As noted above, this is also a solution to the equation for any k. Of course, this distribution is still somewhat degenerate, since the value of a is fixed.
If you want to let all return values be at least somewhat random, you could also pick a random h and return a = −n + h, b = n − 2h + 3k and c = n + h − 5k. Again, this is guaranteed to be a valid solution for any h and k, since it clearly satisfies the equation for h = k = 0, and it's also easy to see that increasing or decreasing either h or k will leave the value of the left-hand side of the equation unchanged.
In fact, it can be proved that this method can generate all possible solutions to the equation, and that each solution will correspond to a unique (h, k) pair! (One fairly intuitive way to see this is to plot the solutions in 3D space and observe that they form a regular lattice of points on a 2D plane, and that the vectors (+1, −2, +1) and (0, +3, −5) span this lattice.) If we pick h and k from some distribution that (at least in theory) assigns a non-zero probability to every integer, then we'll have a non-zero probability of returning any valid solution. So, at least for one somewhat reasonable interpretation of the task (unbounded range, any distribution with full support) the following code should solve the task efficiently:
from random import gauss
def random_solution(n):
h = int(gauss(0, 1000)) # any distribution with full support on the integers will do
k = int(gauss(0, 1000))
return (-n + h, n - 2*h + 3*k, n + h - 5*k)
If the range of possible values is restricted, the problem becomes a bit trickier. On the positive side, if all values are bounded below (or above), then the set of possible solutions is finite, and so a uniform distribution exists on it. On the flip side, efficiently sampling this uniform distribution is not trivial.
One possible approach, which you've used yourself, is to first generate all possible solutions (assuming there's a finite number of them) and then sample from the list of solutions. We can do the solution generation fairly efficiently like this:
find all possible values of a for which the equation might have a solution,
for each such a, find all possible values of b for which there still have a solution,
for each such (a, b) pair, solve the equation for c and check if it's valid (i.e. an integer within the specified range), and
if yes, add (a, b, c) to the set of solutions.
The tricky part is step 2, where we want to calculate the range of possible b values. For this, we can make use of the observation that, for a given a, setting c to its smallest allowed value and solving the equation gives an upper bound for b (and vice versa).
In particular, solving the equation for a, b and c respectively, we get:
a = (n − 5b − 3c) / 7
b = (n − 7a − 3c) / 5
c = (n − 7a − 5b) / 3
Given lower bounds on some of the values, we can use these solutions to compute corresponding upper bounds on the others. For example, the following code will generate all non-negative solutions efficiently (and can be easily modified to use a lower bound other than 0, if needed):
def all_nonnegative_solutions(n):
a_min = b_min = c_min = 0
a_max = (n - 5*b_min - 3*c_min) // 7
for a in range(a_min, a_max + 1):
b_max = (n - 7*a - 3*c_min) // 5
for b in range(b_min, b_max + 1):
if (n - 7*a - 5*b) % 3 == 0:
c = (n - 7*a - 5*b) // 3
yield (a, b, c)
We can then store the solutions in a list or a tuple and sample from that list:
from random import choice
solutions = tuple(all_nonnegative_solutions(30))
a, b, c = choice(solutions)
Ps. Apparently Python's random.choice is not smart enough to use reservoir sampling to sample from an arbitrary iterable, so we do need to store the full list of solutions even if we only want to sample from it once. Or, of course, we could always implement our own sampler:
def reservoir_choice(iterable):
r = None
n = 0
for x in iterable:
n += 1
if randrange(n) == 0:
r = x
return r
a, b, c = reservoir_choice(all_nonnegative_solutions(30))
BTW, we could make the all_nonnegative_solutions function above a bit more efficient by observing that the (n - 7*a - 5*b) % 3 == 0 condition (which checks whether c = (n − 7a − 5b) / 3 is an integer, and thus a valid solution) is true for every third value of b. Thus, if we first calculated the smallest value of b that satisfies the condition for a given a (which can be done with a bit of modular arithmetic), we could iterate over b with a step size of 3 starting from that minimum value and skip the divisibility check entirely. I'll leave implementing that optimization as an exercise.
import numpy as np
def generate_answer(n: int, low_limit:int, high_limit: int):
while True:
a = np.random.randint(low_limit, high_limit + 1, 1)[0]
b = np.random.randint(low_limit, high_limit + 1, 1)[0]
c = (n - 7 * a - 5 * b) / 3.0
if int(c) == c and low_limit <= c <= high_limit:
break
return a, b, int(c)
if __name__ == "__main__":
n = 30
ans = generate_answer(low_limit=-5, high_limit=50, n=n)
assert ans[0] * 7 + ans[1] * 5 + ans[2] * 3 == n
print(ans)
If you select two of the numbers a, b, c, you know the third. In this case, I randomize ints for a, b, and I find c by c = (n - 7 * a - 5 * b) / 3.0.
Make sure c is an integer, and in the allowed limits, and we are done.
If it is not, randomize again.
If you want to generate all possibilities,
def generate_all_answers(n: int, low_limit:int, high_limit: int):
results = []
for a in range(low_limit, high_limit + 1):
for b in range(low_limit, high_limit + 1):
c = (n - 7 * a - 5 * b) / 3.0
if int(c) == c and low_limit <= c <= high_limit:
results.append((a, b, int(c)))
return results
If third-party libraries are allowed, you can use SymPy's diophantine.diop_linear linear Diophantine equations solver:
from sympy.solvers.diophantine.diophantine import diop_linear
from sympy import symbols
from numpy.random import randint
n = 30
N = 8 # Number of solutions needed
# Unknowns
a, b, c = symbols('a, b, c', integer=True)
# Coefficients
x, y, z = 7, 5, 3
# Parameters of parametric equation of solution
t_0, t_1 = symbols('t_0, t_1', integer=True)
solution = diop_linear(x * a + y * b + z * c - n)
if not (None in solution):
for s in range(N):
# -10000 and 10000 (max and min for t_0 and t_1)
t_sub = [(t_0, randint(-10000, 10000)), (t_1, randint(-10000, 10000))]
a_val, b_val, c_val = map(lambda t : t.subs(t_sub), solution)
print('Solution #%d' % (s + 1))
print('a =', a_val, ', b =', b_val, ', c =', c_val)
else:
print('no solutions')
Output (random):
Solution #1
a = -141 , b = -29187 , c = 48984
Solution #2
a = -8532 , b = -68757 , c = 134513
Solution #3
a = 5034 , b = 30729 , c = -62951
Solution #4
a = 7107 , b = 76638 , c = -144303
Solution #5
a = 4587 , b = 23721 , c = -50228
Solution #6
a = -9294 , b = -106269 , c = 198811
Solution #7
a = -1572 , b = -43224 , c = 75718
Solution #8
a = 4956 , b = 68097 , c = -125049
Why your solution can't cope with large values of n
You may understand that everything in a for loop with a range of i, will run i times. So it will multiply the time taken by i.
For example, let's pretend (to keep things simple) that this runs in 4 milliseconds:
if 7*a + 5*b + 3*c = n:
c.append(a)
k.append(b)
w.append(c)
then this will run in 4×n milliseconds:
for c in range(n):
if 7*a + 5*b + 3*c = n:
c.append(a)
k.append(b)
w.append(c)
Approximately:
n = 100 would take 0.4 seconds
n = 250 would take 1 second
n = 15000 would take 60 seconds
If you put that inside a for loop over a range of n then the whole thing will be repeated n times. I.e.
for b in range(n):
for c in range(n):
if 7*a + 5*b + 3*c = n:
c.append(a)
k.append(b)
w.append(c)
will take 4n² milliseconds.
n = 30 would take 4 seconds
n = 50 would take 10 seconds
n = 120 would take 60 seconds
Putting it in a third for-loop will take 4n³ milliseconds.
n = 10 would take 4 seconds
n = 14 would take 10 seconds.
n = 24 would take 60 seconds.
Now, what if you halved the original if to 2 milliseconds? n would be able to increase by 15000 in the first case... and 23 in the last case. The lesson here is that fewer for-loops is usually much more important than speeding up what's inside them. As you can see in Gulzar's answer part 2, there are only two for loops which makes a big difference. (This only applies if the loops are inside each other; if they are just one after another you don't have the multiplication problem.)
from my perspective, the last number of the three is never a random number. let say you generate a and b first then c is never a random because it should be calculated from the equation
n = 7*a + 5*b + 3*c
c = (7*a + 5*b - n) / -3
this means that we need to generate two random values (a,b)
that 7*a + 5*b - n is divisible by 3
import random
n = 30;
max = 1000000;
min = -1000000;
while True:
a = random.randint(min , max);
b = random.randint(min , max);
t = (7*a) + (5*b) - n;
if (t % 3 == 0) :
break;
c = (t/-3);
print("A = " + str(a));
print("B = " + str(b));
print("C = " + str(c));
print("7A + 5B + 3C =>")
print("(7 * " + str(a) + ") + (5 * " + str(b) + ") + (3 * " + str(c) + ") = ")
print((7*a) + (5*b) + (3*c));
REPL
I am just looking at the Python module SymPy and try, as a simple (useless) example the fit of a function f(x) by a function set g_i(x) in a given interval.
import sympy as sym
def functionFit(f, funcset, interval):
N = len(funcset) - 1
A = sym.zeros(N+1, N+1)
b = sym.zeros(N+1, 1)
x = sym.Symbol('x')
for i in range(N+1):
for j in range(i, N+1):
A[i,j] = sym.integrate(funcset[i]*funcset[j],
(x, interval[0], interval[1]))
A[j,i] = A[i,j]
b[i,0] = sym.integrate(funcset[i]*f, (x, interval[0], interval[1]))
c = A.LUsolve(b)
u = 0
for i in range(len(funcset)):
u += c[i,0]*funcset[i]
return u, c
x = sym.Symbol('x')
f = 10*sym.cos(x)+3*sym.sin(x)
fooset=(sym.sin(x), sym.cos(x))
interval = (1,2)
print("function to approximate:", f)
print("Basic functions:")
for foo in fooset:
print(" - ", foo)
u,c = functionFit(f, fooset, interval)
print()
print("simplified u:")
print(sym.simplify(u))
print()
print("simplified c:")
print(sym.simplify(c))
The result is the fit function u(x), to be returned, together with the coefficients by functionFit.
In my case
f(x) = 10 * sym.cos(x) + 3 * sym.sin(x)
and I want to fit it according to a linear combination of sin(x), cos(x).
So the coefficients should be 3 and 10.
The result is OK, but for u(x) I get
u(x) = (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2))) :
Function to approximate: 3*sin(x) + 10*cos(x)
Basic functions:
- sin(x)
- cos(x)
Simplified u: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
Simplified c: Matrix([[3], [10]])
which is indeed the same as 10 * cos(x) + 3 * sin(x).
However I wonder why it is not simplified to that expression. I tried several simplifying function available, but none of it gives the expected result.
Is there something wrong in my code or are my expectations to high?
Don't know if this is a solution for you, but I'd simply use the .evalf method of every Sympy expression
In [26]: u.simplify()
Out[26]: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
In [27]: u.evalf()
Out[27]: 3.0*sin(x) + 10.0*cos(x)
In [28]:
I'm trying a challenge. The idea is the following:
"Your task is to construct a building which will be a pile of n cubes.
The cube at the bottom will have a volume of n^3, the cube above will
have volume of (n-1)^3 and so on until the top which will have a
volume of 1^3.
You are given the total volume m of the building. Being given m can
you find the number n of cubes you will have to build? If no such n
exists return -1"
I saw that apparently:
2³ + 1 = 9 = 3² and 3 - 1 = 2
3³ + 2³ + 1 = 36 = 6² and 6 - 3 = 3
4³ + 3³ + 2³ + 1 = 100 = 10² and 10 - 6 = 4
5³ + 4³ + 3³ + 2³ + 1 = 225 = 15² and 15 - 10 = 5
6³ + 5³ + 4³ + 3³ + 2³ + 1 = 441 = 21² and 21 - 15 = 6
So if I thought, if I check that a certain number is a square root I can already exclude a few. Then I can start a variable at 1 at take that value (incrementing it) from the square root. The values will eventually match or the former square root will become negative.
So I wrote this code:
def find_nb(m):
x = m**0.5
if (x%1==0):
c = 1
while (x != c and x > 0):
x = x - c
c = c + 1
if (x == c):
return c
else:
return -1
return -1
Shouldn't this work? What am I missing?
I fail a third of the sample set, per example: 10170290665425347857 should be -1 and in my program it gives 79863.
Am I missing something obvious?
You're running up against a floating point precision problem. Namely, we have
In [101]: (10170290665425347857)**0.5
Out[101]: 3189089316.0
In [102]: ((10170290665425347857)**0.5) % 1
Out[102]: 0.0
and so the inner branch is taken, even though it's not actually a square:
In [103]: int((10170290665425347857)**0.5)**2
Out[103]: 10170290665425347856
If you borrow one of the many integer square root options from this question and verify that the sqrt squared gives the original number, you should be okay with your algorithm, at least if I haven't overlooked some corner case.
(Aside: you've already noticed the critical pattern. The numbers 1, 3, 6, 10, 15.. are quite famous and have a formula of their own, which you could use to solve for whether there is such a number that works directly.)
DSM's answer is the one, but to add my two cents to improve the solution...
This expression from Brilliant.org is for summing cube numbers:
sum of k**3 from k=1 to n:
n**2 * (n+1)**2 / 4
This can of course be solved for the total volume in question. This here is one of the four solutions (requiring both n and v to be positive):
from math import sqrt
def n(v):
return 1/2*(sqrt(8*sqrt(v) + 1) - 1)
But this function also returns 79863.0. Now, if we sum all the cube numbers from 1 to n, we get a slightly different result due to the precision error:
v = 10170290665425347857
cubes = n(v) # 79863
x = sum([i**3 for i in range(cubes+1)])
# x = 10170290665425347857, original
x -> 10170290665425347856
I don't know if your answer is correct, but I have another solution to this problem which is waaaay easier
def max_level(remain_volume, currLevel):
if remain_volume < currLevel ** 3:
return -1
if remain_volume == currLevel ** 3:
return currLevel
return max_level(remain_volume - currLevel**3, currLevel + 1)
And you find out the answer with max_level(m, 0). It takes O(n) time and O(1) memory.
I have found a simple solution over this in PHP as per my requirement.
function findNb($m) {
$total = 0;
$n = 0;
while($total < $m) {
$n += 1;
$total += $n ** 3;
}
return $total === $m ? $n : -1;
}
In Python it would be:
def find_nb(m):
total = 0
n = 0
while (total < m):
n = n + 1
total = total + n ** 3
return n if total == m else -1
New to Python and not sure why my fermat factorisation method is failing? I think it may have something to do with the way large numbers are being implemented but I don't know enough about the language to determine where I'm going wrong.
The code below works when n=p*q is made with p and q extremely close (as in within about 20 of each other) but seems to run forever if they are further apart. For example, with n=991*997 the code works correctly and executes in <1s, likewise for n=104729*104659. If I change it ton=103591*104659 however, it just runs forever (well, I let it go 2 hours then stopped it).
Any points in the right direction would be greatly appreciated!
Code:
import math
def isqrt(n):
x = n
y = (x + n // x) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
n=103591*104729
a=isqrt(n) + 1
b2=a*a - n
b=isqrt(b2)
while b*b!=b2:
a=a+1
b2=b2+2*a+1
b=isqrt(b2)
p=a+b
q=a-b
print('a=',a,'\n')
print('b=',b,'\n')
print('p=',p,'\n')
print('q=',q,'\n')
print('pq=',p*q,'\n')
print('n=',n,'\n')
print('diff=',n-p*q,'\n')
I looked up the algorithm on Wikipedia and this works for me:
#from math import ceil
def isqrt(n):
x = n
y = (x + n // x) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x
def fermat(n, verbose=True):
a = isqrt(n) # int(ceil(n**0.5))
b2 = a*a - n
b = isqrt(n) # int(b2**0.5)
count = 0
while b*b != b2:
if verbose:
print('Trying: a=%s b2=%s b=%s' % (a, b2, b))
a = a + 1
b2 = a*a - n
b = isqrt(b2) # int(b2**0.5)
count += 1
p=a+b
q=a-b
assert n == p * q
print('a=',a)
print('b=',b)
print('p=',p)
print('q=',q)
print('pq=',p*q)
return p, q
n=103591*104729
fermat(n)
I tried a couple test cases. This one is from the wikipedia page:
>>> fermat(5959)
Trying: a=78 b2=125 b=11
Trying: a=79 b2=282 b=16
a= 80
b= 21
p= 101
q= 59
pq= 5959
(101, 59)
This one is your sample case:
>>> fermat(103591*104729)
Trying: a=104159 b2=115442 b=339
a= 104160
b= 569
p= 104729
q= 103591
pq= 10848981839
(104729, 103591)
Looking at the lines labeled "Trying" shows that, in both cases, it converges quite quickly.
UPDATE: Your very long integer from the comments factors as follows:
n_long=316033277426326097045474758505704980910037958719395560565571239100878192955228495343184968305477308460190076404967552110644822298179716669689426595435572597197633507818204621591917460417859294285475630901332588545477552125047019022149746524843545923758425353103063134585375275638257720039414711534847429265419
fermat(n_long, verbose=False)
a= 17777324810733646969488445787976391269105128850805128551409042425916175469326288448917184096591563031034494377135896478412527365012246902424894591094668262
b= 157517855001095328119226302991766503492827415095855495279739107269808590287074235
p= 17777324810733646969488445787976391269105128850805128551409042425916175469483806303918279424710789334026260880628723893508382860291986009694703181381742497
q= 17777324810733646969488445787976391269105128850805128551409042425916175469168770593916088768472336728042727873643069063316671869732507795155086000807594027
pq= 316033277426326097045474758505704980910037958719395560565571239100878192955228495343184968305477308460190076404967552110644822298179716669689426595435572597197633507818204621591917460417859294285475630901332588545477552125047019022149746524843545923758425353103063134585375275638257720039414711534847429265419
The error was doing the addition after incremeting a so the new value was not the square of a.
This works as intended :
while b*b!=b2:
b2+=2*a+1
a=a+1
b=isqrt(b2)
for big numbers it should be faster than computing the square which has quite a greater number of digits.