Optimization of algebraic computation - performance

Using mathematica, I can compute the mathematical representation of a function that I then want to code in C++.
Say I get something like:
f=Log[2*x+3*y]+Sin[4*x+6*y]
It obviously makes sense in that case to do the computation:
temp=2*x+3*y
f=Log[temp]+Sin[2*temp]
Is there a way to get the expression that would reduce the execution time / number of operations / size of the expression or any good metric given a more complex mathematical expression?

Although it doesn't work for your simple example, what you can try is the following in Mathematica
Experimental`OptimizeExpression[{Log[(2*x^3 + 3*y)^2] + Sin[2 (2*x^3 + 6*y)^2]}]
As result you get
Experimental`OptimizedExpression[
Block[{Compile`$3, Compile`$4}, Compile`$3 = x^3;
Compile`$4 = 2 Compile`$3;
{Log[(Compile`$4 + 3 y)^2] + Sin[2 (Compile`$4 + 6 y)^2]}]]

Related

Is there a way to know when parseFloat or Float number precision will be wrong?

Okay so I've read few things about this topic :
How to deal with floating point number precision in JavaScript?
Is floating point math broken?
Why can't decimal numbers be represented exactly in binary?
My question isn't why it's happening, or how to solve it.
It's about if there is a way to predict that it will happen, and then use a solution only if it'll happen. And more than just this, I'd like a low computation cost solution.
I ran few tests, and I feel like there are conditions required for this kind of problem to happen, but I'm not sure about them :
console.log("1st calc", parseFloat(-24.05) + parseFloat(24.05));
console.log("2nd calc", parseFloat(-12.003) + parseFloat(12.003) + parseFloat(-24.05) + parseFloat(24.05));
console.log("3rd calc", parseFloat(-12.003) + parseFloat(-24.05) + parseFloat(12.003) + parseFloat(24.05));
console.log("4th calc", parseFloat(12.003) + parseFloat(24.05) + parseFloat(-12.003) + parseFloat(-24.05));
console.log("5th calc", parseFloat(12.006) + parseFloat(-12.006) + parseFloat(2.007) + parseFloat(-2.007) + parseFloat(1.009) + parseFloat(-1.009));
console.log("6th calc", parseFloat(12.006) + parseFloat(2.007) + parseFloat(1.009) + parseFloat(-12.006) + parseFloat(-2.007) + parseFloat(-1.009));
console.log("7th calc", parseFloat(12.05) + parseFloat(2.003) + parseFloat(1.005) + parseFloat(7.01) + parseFloat(-12.05) + parseFloat(-2.003) + parseFloat(-1.005) + parseFloat(-7.01));
console.log("8th calc", parseFloat(12.05) + parseFloat(-12.05) + parseFloat(2.003) + parseFloat(-2.003) + parseFloat(1.005) + parseFloat(-1.005) + parseFloat(7.01) + parseFloat(-7.01));
I got it that it's about whether the number has an exact binary representation or not, but to know this it's a long computation, so is there a faster/easier way to predict it or not ?
The thing is, I'd like to have a script that tests if it has an exact binary representation or not, and then apply a solution only if needed. But I'd like it to be faster than just apply the solution to every float. I don't know if it's possible.
Something like
def power_of_2?(number)
return true if number == 1
return false if number == 0 || number % 2 != 0
power_of_2?(number / 2)
end
Might help to know wether the number has an exact binary representation, but I'm not even sure it's accurate enough for numbers such as 1.300005407.
For example, using the numbers I wrote in the tests above, I feel like it's faster to multiply them all by 1000 inside the parseFloat() (which solves the problem here) than testing them one by one.
Something I noticed too with my tests, is that according to the way you add the numbers, the problem occurs or not :
console.log("7th calc", parseFloat(12.05) + parseFloat(2.003) + parseFloat(1.005) + parseFloat(7.01) + parseFloat(-12.05) + parseFloat(-2.003) + parseFloat(-1.005) + parseFloat(-7.01));
console.log("8th calc", parseFloat(12.05) + parseFloat(-12.05) + parseFloat(2.003) + parseFloat(-2.003) + parseFloat(1.005) + parseFloat(-1.005) + parseFloat(7.01) + parseFloat(-7.01));
uses the same numbers, just not in the same order and give a totally different result.
Any idea ?
Well, the stupidly easy, but not perfect, approach is to parse at higher precision than you need, and check that converting to your desired precision doesn't change the value. That isn't quite right, since the rare value will not be representable as a double, but the closest double representation will be an exact float (e.g. 1.00000000000000001).
The perfect but not necessarily practical approach is to parse twice, each time with a different floating point rounding mode: First round-to-plus-infinity, then round-to-minus-infinity. If the two results are the same, the input was exactly representable. The problem is, not all string-to-float implementations behave properly WRT rounding mode, so you'll need to test whether this works for you. (And, of course, this is only relevant in environments where you get to control the rounding mode.) This approach is also appropriate for operations other than string-to-float, but there are better-adapted methods for certain operations like subtraction.
You might also consider converting the floating-point value back to a string and doing string comparison. That's fiddly, though, since you'll have to worry about whether your input is in canonical form.

Math function with three variables (correlation)

I want to analyse some data in order to program a pricing algorithm.
Following dates are available:
I need a function/correlationfactor of the three variables/dimension which show the change of the Median (price) while the three dimensions (pers_capacity, amount of bedrooms, amount of bathrooms) grow.
e.g. Y(#pers_capacity,bedroom,bathroom) = ..
note:
- in the screenshot below are not all the data available (just a part of it)
- median => price per night
- yellow => #bathroom
e.g. For 2 persons, 2 bedrooms and 1 bathroom is the median price 187$ per night
Do you have some ideas how I can calculate the correlation/equation (f(..)=...) in order to get a reliable factor?
Kind regards
One typical approach would be formulating this as a linear model. Given three variables x, y and z which explain your observed values v, you assume v ≈ ax + by + cz + d and try to find a, b, c and d which match this as closely as possible, minimizing the squared error. This is called a linear least squares approximation. You can also refer to this Math SE post for one example of a specific linear least squares approximation.
If your your dataset is sufficiently large, you may consider more complicated formulas. Things like
v ≈
a1x2 +
a2y2 +
a3z2 +
a4xy +
a5xz +
a6yz +
a7x +
a8y +
a9z +
a10
The above is non-linear in the variables but still linear in the coefficients ai so it's still a linear least squares problem.
Or you could apply transformations to your variables, e.g.
v ≈
a1x +
a2y +
a3z +
a4exp(x) +
a5exp(y) +
a6exp(z) +
a7
Looking at the residual errors (i.e. difference between predicted and observed values) in any of these may indicate terms worth adding.
Personally I'd try all this in R, since computing linear models is just one line in that language, and visualizing data is fairly easy as well.

Characteristic Equation of A Closed Loop System in Terms of PI Controller

Just wondering if you could guide me on how to find the characteristic equation of a trasfer function G(s) (see below for G(s)) in terms of the coefficients in the PI controller?
G(s) = 45/(5s + 2)
No sure what to do here, as I'm used to just multiplying the error by the proportional gain - but there's no error value provided.
Any advice would be much appreciated. Thanks in advance ;)
Given:
G(s) = 45/(5s + 2) (plant transfer function)
C(s) = Kp + Ki/s (PI Controller transfer function)
and assuming your system looks like:
https://www.dropbox.com/s/wtt4tvujn6tpepv/block_diag.JPG
The equation of the closed loop transfer function is:
Gcl(s) = C(s)G(s)/(1+C(s)G(s)) = CG/(1+CG)
In general, If you had another transfer function on the feedback path, H(s),
the the closed loop transfer function becomes:
CG / (1 + CGH)
If you plug in G(s) and C(s) as shown above you will get the following closed loop transfer function after some algebraic simplification:
45*[Kp*s + Ki] / [5*s*s + (2 + 45*Kp)*s + 45*Ki]
and so the characteristic equation is
5*s*s + (2 + 45*Kp)*s + 45*Ki = 0
Notice how the integral term adds a pole to the system but has a side effect of also adding a zero which could produce unwanted transient behaviour if Kp is not chosen correctly. The presence of Kp in the s term in the denominator shows that the value of Kp will determine the damping ratio of the system and therefore determine the transient response.
More information on poles, zeros, and system dynamics:
http://web.mit.edu/2.14/www/Handouts/PoleZero.pdf

fast multiplications

When I am going to compute the following series 1+x+x^2+x^3+..., I would prefer to do like this: (1+x)(1+x^2)(1+x^4)... (which is like some sort of repeated squaring) so that the number of multiplications can be significantly reduced.
Now I want to compute the series 1+x/1!+(x^2)/2!+(x^3)/3!+..., how can I use the similar techniques to improve the number of multiplications?
Any suggestions are warmly welcome!
The method of optimization you refer, is probably Horner's method:
a + bx +cx^2 +dx^3 = ((c+dx)x + b)x + a
The alternating series A*(1-x)(1+x^2)(1-x^4)(1+x^8) ... OTOH is useful in calculating approximation for division of A/(1+x), where x is small.
The Taylor series sigma x^n/n! for exp(x) converges quite badly; other approximations are better suited to get accurate values; if there's a trick to make it with less multiplications, it is to iterate with a temporary value:
sum=1; temp=x; k=1;
// The sum after first iteration is (1+x) or 1+x^1/1!
for (i=1;i<=N;i++) { sum=sum+temp; k=k*(i+1); temp = temp * x / k; }
// or
prod=1.0; for (i=N;i>0;i--) prod = prod * x/(double)i + 1.0;
Multiplying the factorial should increase accuracy a bit -- in real life situation it's may be advisable to either combine temp=temp*x/(i+1) in order to be able to iterate much further, or to use a lookup table for the constant a_n / n!, as one typically needs just a few terms. (4 or 5 terms for sin/cos).
As it turned out, Horner's rule didn't have much role in the transformation of the geometric series Sigma x^n to product form. To calculate exponential, other powerful techniques have to be applied -- typically range reduction and rational (Pade), polynomial (chebyshev) approximations and such.
Converting comment to an answer:
Note that for first series, there is exact equivalence:
1+x+x^2+x^3+...+x^n = (1-x^(n+1))/(1-x)
Using it, you can compute it much, much faster.
Second one is convergence series for e^x, you might want to use standard math library functions pow(e, x) or exp(x) instead.
On your approach for the first series don't you think that using 1 + x(1+ x( 1+ x( 1+x)....)) would be a better approach. Similar approach can be applied for the second series. So 1 + x/1 ( 1+ x/2 (1 + x/3 * (1 + x/4(.....))))

Performance of Fibonacci

f[0] = 0;
f[1] = 1;
f[x_] := f[x-1] + f[x-2]
This function is running slow in Mathematica and I need to increase the speed. I have to use functional programming and recursion. I'm not sure why this is running so slow, and even the slightest idea how to improve this would be helpful.
A good way to write a faster recursive function is to have it memorize previous values. This does come at the cost of memory, of course, but it can help in cases like this. In order to calculate f[x], you calculate f[x-1] and f[x-2] - and then to calculate f[x-1], you calculate f[x-2] again; you end up recalculating a lot of values a lot of times. (Forgive my imprecision!)
To store things as you go, you can use this idiom:
f[x_] := ( f[x] = (* calculation of f[x] goes here *) )
Edit: I don't have mathematica on this machine, but I'm pretty sure there's no way this computes the wrong value.
f[0] = 0;
f[1] = 1;
f[x_] := ( f[x] = f[x-1] + f[x-2] );
f[256]
Like I said in a comment below, if you have other definitions of f, you might want to wipe them out first with Clear[f].
Thanks to rcollyer: Be careful about $RecursionLimit! It defaults to 256. (Of course, this is with good reason. Really deep recursion is usually a bad idea.)
Jefromi is right. Look at Memoization on wikipedia. They use the example of factorial and how to speed it up with memoization.
Memoization is a good way to write a faster recursive function. However, in this case there is a recursive alternative that runs tremendously faster than original function, without requiring memoization.
The key observation is to see that the original definition performs a lot of redundant calculations. Consider what happens if we calculate fib[4]:
fib[4] = fib[3] + fib[2]
fib[3] = fib[2] + fib[1]
fib[2] = fib[1] + fib[0]
fib[1] = 1
fib[0] = 1
∴ fib[2] = 1 + 1 = 2
fib[1] = 1
∴ fib[3] = 2 + 1 = 3
fib[2] = fib[1] + fib[0]
fib[1] = 1
fib[0] = 1
∴ fib[2] = 1 + 1 = 2
∴ fib[4] = 2 + 1 = 3
In this process, fib[2] and fib[0] were computed twice each and fib[1] was computed thrice. For larger computations, the waste grows dramatically -- exponentially in fact.
If one were to calculate the same Fibonacci number by hand, one might proceed something like this:
0: given 0
1: given 1
2: 0 + 1 = 1
3: 1 + 1 = 2
4: 1 + 2 = 3
There are no redundant calculations. At any given point, one only needs to consider the previous two results. This latter approach can be expressed recursively thus:
fib2[0] = 0;
fib2[n_] :=
Module[{f},
f[n, p1_, _] := p1;
f[x_, p1_, p2_] := f[x + 1, p1 + p2, p1];
f[1, 1, 0]
]
Block[{$IterationLimit = Infinity}, fib2[100000]]
No doubt, this form is not as easy to read as the original. On the other hand, the original function took 35 seconds to compute fib[35] on my machine whereas the revised function's runtime for same was reported as zero. Furthermore, the revised function computes fib2[100000] in 0.281 seconds, without requiring any of the extra storage of memoization. fib[100000] is quite out of reach of the original function and the memoized version crashed my Mathematica 7.01 kernel -- too many memoized rules perhaps?
Note that Mathematica, by default, will iterate a function no more than 4096 times. To raise that limit, you must assign a higher value to $IterationLimit as illustrated in the example above.
Of course, in Mathematica there are plenty of non-recursive ways to calculate Fibonacci numbers, up to and including the built-in Fibonacci function. But that is not the point of this exercise.
Tail Call Optimization?
It is always desirable to express recursive functions using tail calls. This permits the recursion to be executed by simple iteration, without the overhead of retaining intermediate results on the stack. fib2 is tail recursive. Some languages, like Scheme, mandate tail call optimization. Other languages, like Java, could support it but don't (or won't, as in the case of Python).
In the case of Mathematica, it is not clear to what extent tail call optimization is performed. For further discussion of this point, see another SO question.

Resources