I am looking to perform a summation that, for the sake of this question, can take the form:
NOTE: Apologies, I have changed the equation as the original was not getting the problem across in the way I intended.
Ideally I would like to solve f(t) without using a for loop, as there are lots of different values of n and t to pass in. For example, the worst case scenario would be two for loops, taking the form:
import numpy as np
import math
for t in range(len(ft)):
sum=0
for n in range(1,len(N)):
sum += np.sin(math.pow(n,2) * t)
ft[t] = sum
I have improved this to only have one for loop, taking the form:
for t in range(len(ft)):
n = np.arange(1,N)
ft[t] = np.sum(np.sin(math.pow(n,2) * t))
Is there a way of further simplifying this to avoid having to iterate through all values of t? For my purposes, the summation that I need is too time expensive while having to loop through all values of t.
UPDATE: The actual equation I have trying to solve, since simplifying it for the sake of finding a solution appears to be causing confusion, is:
I can simplify it down to a single for loop through the range of t values (similar to the example shown). I am hoping to simplify it further as there are about 90000 t values to iterate through.
Sine is a periodic function. You can exploit this to perform a smaller number of sums than N sums as values will repeat - if not exactly due to number spacings, you can find the relative phaseshift to change the summed values for each new period within N terms.
You can perform Einstein summation in numpy to avoid for loops
np.sin(np.einsum('i,ji',np.arange(1,N)**2,np.tile(np.arange(len(ft))[:,None],N-1)))
Maybe I didn't get the question, but isn't it as simple as:
mysum(t, N):
return sum(map(lambda n : sin(t*n*n), range(N)))
Related
I was traying to write a code that calculate the sum of 2*j+i+1 where 0<=j<=i<=n but I wasn't very optimazed
there are my code :
def get_sum(n):
s=0
for j in range(n+1):
ss=0
ss=sum(2*j+i+1 for i in range(j,n+1))
s+=ss
return s
Write to calculate a a sum of 2*j+i+1 where 0<=j<=i<=n but it wasn't optimazed
Before delving into optimizing the code, always take a step back and consider what the code does. In this case, try to solve the equations with pen and paper, instead of brute-forcing them with a computer.
The value you want, lets call it S is defined as
Compute the inner sum first
And, finally, substitute and compute the outer sum
The second to last expression is the fastest one to use, as it uses fewer multiplications (and an "easier" division). If you are unfamiliar with any of the math above, look up the basic summation properties and identities.
And your function is simply
def get_sum(n):
return (n+1)*(n+2)*(4*n+3)/2
This is really just a math question:
def get_sum2(n):
return (4*n*n*n + 15*n*n + 17*n + 6)/6
As you mentioned that you want to simplify the code:
sum([2*j+i+1 for i in range(n+1) for j in range(i+1)])
suppose I have a few lists
b_wi=[[1,2,3,4],[6,7,8,9,10,11]] #b_wi is a subset of x
f_wi=[[5,4,2,7,9],[5,4,3,7,2,3,4]]
x=[[1,2,3,4,5,6,7,8,9,2,5,3],[1,24,36,42,35,6,7,8,91,2,5,3]]
the following two are step functions formed by the above lists.
'''
F1 = f_wi[0][0] if x< b_wi[0][0] ;
f_wi[0][1] if b_wi[0][0] <=x< b_wi[0][1];
...;
f_wi[0][-1] if x>= b_wi[1][-1]
F2 = f_wi[1][0] if x< b_wi[1][0] ;
f_wi[1][1] if b_wi[1][0] <=x< b_wi[1][1];
...;
f_wi[1][-1] if x>= b_wi[1][-1]
'''
Now I want to get max (F1+F2) and the corresponding interval.
I did some searching and found this :
Evaluate sum of step functions
However, since the length of intervals is not the same for these step functions, I cannot apply the solution in the link directly.
Instead, I did this:
import numpy as np
from pandas.core.common import flatten
def func(x,b,f):
return f[np.searchsorted(b,x,side='right')]
intval= np.unique(list(flatten(b_wi)))
x=np.concatenate(([-10000],(intval[:-1]+intval[1:])/2,[10000])) #b_wi is a subset of x. That is why I can use this.
a=np.zeros((len(x)))
for b, f in zip(b_wi,f_wi):
a=a+ func(x,b,np.asarray(f))
print(a/2)
Now I get can get the maximum of (F1+F2) using
np.amax(a)
and I can get the interval as well.
This is just a simple example I used to illustrate my question. My actual lists are longer than these and there are 100000 step functions. Since I 'flatten' 'b_wi' in order to find the corresponding interval, the length of 'intval' becomes too large. Hence, my method is too slow.
Does anyone know how I could speed it up? I feel like I am using the wrong method.
Thank you very much.
I am trying to solve this problem: '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 the 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?
The parameter of the function findNb (find_nb, find-nb, findNb) will be an integer m and you have to return the integer n such as n^3 + (n-1)^3 + ... + 1^3 = m if such a n exists or -1 if there is no such n.'
I tried to first create an arithmetic sequence then transform it into a sigma sum with the nth term of the arithmetic sequence, the get a formula which I can compare its value with m.
I used this code and work 70 - 80% fine, most of the calculations that it does are correct, but some don't.
import math
def find_nb(m):
n = 0
while n < 100000:
if (math.pow(((math.pow(n, 2))+n), 2)) == 4*m:
return n
break
n += 1
return -1
print(find_nb(4183059834009))
>>> output 2022, which is correct
print(find_nb(24723578342962))
>>> output -1, which is also correct
print(find_nb(4837083252765022010))
>>> real output -1, which is incorrect
>>> expected output 57323
As mentioned, this is a math problem, which is mainly what I am better at :).
Sorry for the in-line mathematical formula as I cannot do any math formula rendering (in SO).
I do not see any problem with your code and I believe your sample test case is wrong. However, I'll still give optimisation "tricks" below for your code to run quicker
Firstly as you know, sum of the cubes between 1^3 and n^3 is n^2(n+1)^2/4. Therefore we want to find integer solutions for the equation
n^2(n+1)^2/4 == m i.e. n^4+2n^3+n^2 - 4m=0
Running a loop for n from 1 (or in your case, 2021) to 100000 is inefficient. Firstly, if m is a large number (1e100+) the complexity of your code is O(n^0.25). Considering Python's runtime, you can run your code in time only if m is less than around 1e32.
To optimise your code, you have two approaches.
1) Use Binary Search. I will not get into the details here, but basically, you can halve the search range for a simple comparison. For the initial bounds you can use lower = 0 & upper = k. A better bound for k will be given below, but let's use k = m for now.
Complexity: O(log(k)) = O(log(m))
Feasible range for m: m < 10^(3e7)
2) Use the almighty Newton-Raphson!! Using the iteration formula x_(n+1) = x_n - f(x_n) / f'(x_n), where f'(x) can be calculated explicitly, and a reasonable initial guess, let's say k = m again, the complexity is (I believe) O(log(k)) + O(1) = O(log(m)).
Complexity: O(log(k)) = O(log(m))
Feasible range for m: m < 10^(3e7)
Finally, I'll give a better initial guess for k in the above methods, also given in Ian's answer to this question. Since n^4+2n^3+n^2 = O(n^4), we can actually take k ~ m^0.25 = (m^0.5)^0.5. To calculate this, We can take k = 2^(log(k)/4) where log is base 2. The log should be O(1), but I'm not sure for big numbers/dynamic size (int in Python). Not a theorist. Using this better guess and Newton-Raphson, since the guess is in a constant range from the result, the algorithm is nearly O(1). Again, check out the links for better understanding.
Finally
Since your goal is to find whether n exists such that the equation is "exactly satisfied", use Newton-Raphson and iterate until the next guess is less than 0.5 from the current guess. If your implementation is "floppy", you can also do a range +/- 10 from the guess to ensure that you find the solution.
I think this is a Math question rather than a programming question.
Firstly, I would advise you to start iterating from a function of your input m. Right now you are initialising your n value arbitrarily (though of course it might be a requirement of the question) but I think there are ways to optimise it. Maybe, just maybe you can iterate from the cube root, so if n reaches zero or if at any point the sum becomes smaller than m you can safely assume there is no possible building that can be built.
Secondly, the equation you derived from your summation doesn't seem to be correct. I substituted your expected n and input m into the condition in your if clause and they don't match. So either 1) your equation is wrong or 2) the expected output is wrong. I suggest that you relook at your derivation of the condition. Are you using the sum of cubes factorisation? There might be some edge cases that you neglected (maybe odd n) but my Math is rusty so I can't help much.
Of course, as mentioned, the break is unnecessary and will never be executed.
I'm interested to compute a quantity log(| sum_i [(x_i)^3] |); The problem of directly using np.log(abs((x**3).sum())) (where x is a array of elements, and x**3 is to apply cube function element wisely to the array) is that some values in x**3 could be so large and has potential numerical issues.
My plan is to use logsumexp trick. However, the absolute value outside of the sum is hard to get rid of. Any help?
We can use a little bit of math to avoid numerical overflow.
Suppose x is an numpy array.
The problem comes from the abs((x**3).sum()), specifically the cubing operation. We can make the computation more stable by scaling down each number in x by a constant. Because we are dividing by a constant inside the array before the cubing, we need to multiply by the constant cubed outside the summation.
In other words:
abs((x**3).sum()) = (constant**3)*abs(((x/constant)**3).sum())
Using properties of logs, you can simplify your final expression to the following:
np.log(constant**3) + np.log(abs(((x/constant)**3).sum(0)))
I have complex algorithm to build in order to select the best combination of elements in my list.
I have a list of 20 elements. I make all the combinations this list using this algorithms, the resutlt would be a list of element with size: 2^20-1 (without duplications)
from itertools import combinations
def get_all_combinations(input_list):
for i in xrange(len(input_list)):
for item in combinations(input_list, r = i + 1):
yield list(item)
input_list = [1,4,6,8,11,13,5,98,45,10,21,34,46,85,311,133,35,938,345,310]
print len(get_all_combinations(input_list)) # 1048575
I have another algorithm that is applied on every list, then calculate the max.
// this is just an example
def calcul_factor(item):
return max(item) * min(item) / sqrt(min(item))
I tried to do it like this way: but it's taking a long time.
columnsList= get_all_combinations(input_list)
for x in columnsList:
i= calcul_factor(x)
factorsList.append(i)
l.append(x)
print "max", max(factorsList)
print "Best combinations:", l[factorsList.index( max(factorsList))]
Does using Maps/Lamda expressions solve issues to make "parallelisme" to calculate the maximum ?
ANy hints to do that ?
In case you can't find a better algorithm (which might be needed here) you can avoid creating those big lists by using generators.
With the help of itertools.chain you can combine the itertools.combinations-generators. Furthermore the max-function can take a function as a key.
Your code can be reduced to:
all_combinations = chain(*[combinations(input_list, i) for i in range(1, len(input_list))])
max(all_combinations, key=algorithm)
Since this code relies solely on generators it might be faster (doesn't mean fast enough).
Edit: I generally agree with Hugh Bothwell, that you should be trying to find a better algorithm before going with an implementation like this. Especially if your lists are going to contain more than 20 elements.
If you can easily calculate calcul_factor(item + [k]) given calcul_factor(item), you might greatly benefit from a dynamic-programming approach.
If you can eliminate some bad solutions early, it will also greatly reduce the total number of combinations to consider (branch-and-bound).
If the calculation is reasonably well-behaved, you might even be able to use ie simplex method or a linear solver and walk directly to a solution (something like O(n**2 log n) runtime instead of O(2**n))
Could you show us the actual calcul_factor code and an actual input_list?