grame-cncm / faust

Functional programming language for signal processing and sound synthesis
http://faust.grame.fr
Other
2.58k stars 322 forks source link

Trigonometric simplifications #59

Open sekisushai opened 7 years ago

sekisushai commented 7 years ago

Hello,

I'm posting this issue -more as an feature request- about trigonometric simplifications.

For some applications, I manipulate trigonometric functions (spherical harmonics) and depending on the algorithm, the output formula could be very complicated.

However, in a lot of cases, trigonometric identities could help to simplify drastically the expressions.

For example, as pointed in this issue: https://github.com/grame-cncm/faust/issues/56, the algorithm outputs a matrix where all terms are functions which can be simplified in the majority of the cases. However, the output terms are not given in their simplest form, so far. For example, the term rot(2,1,1) in the algorithm described in the aforementioned issue gives:

rot(2,1,1) = cos(pitch)^2*cos(roll)*cos(yaw) +
 sin(pitch)*(-cos(roll)*cos(yaw)*sin(pitch) + sin(roll)*sin(yaw))

Which, after factorization gives rot(2,1,1) = cos(roll)*cos(yaw)*(cos(pitch)^2 - sin(pitch)^2)) + sin(pitch)*sin(roll)*sin(yaw) This latter expression is the output proposed by the compiler.

However, knowing that cos(pitch)^2 - sin(pitch)^2 = cos(2*pitch) the previous expression could be simplified with: rot(2,1,1) = cos(roll)*cos(yaw)*cos(2*pitch) + sin(pitch)*sin(roll)*sin(yaw) which is a simpler expression.

Following this example, I'm wondering if it is possible for the compiler to recognize trigonometric identities, typically as given in the following link: http://artemath.com/artemath/cours/documents/docs/formulaire-trigo.pdf

Thank you ! Pierre

sletz commented 7 years ago

Having symbolic computation on mathematical expressions would certainly by very interesting... The thing is that the question (in general...) seems quite large:

Any insight would be welcome..

sekisushai commented 7 years ago

For my applications, the first criterion for simplification is the lowest computation cost. I guess it associated with the simplest mathematical expression.

In fact, some algorithms never compiles because of too complex expressions and high computation cost. If it compiles it is often very CPU consuming while a lot of terms could be computed with simpler mathematical expressions or are even 0 ('cos(ma.PI/2)', 'sin(ma.PI)', ...).

I have no idea how a symbolic computation system is integrable in Faust and at which point. But as for factorization, the compiler could maybe at least recognize some mathematical identities ..?

About precision, my thought is that symbolic form could help to gain a lot computation cost, especially with trigonometry. For example with the number 'PI'. If 'cos(ma.PI/2)' gives a true '0' (and not '6.123233995736766e-17' in double precision), it could simplify the output at compilation time, or if use in association with some sliders, it could be associated with the primitives ‘control' or ‘enable’ and save a some computations at execution time.

josmithiii commented 7 years ago

This is an interesting problem. I would try Wolfram Alpha for such simplifications, and after that, Mathematica or Maxima. My experience (mostly with Maxima and Macsyma before that) has been that the symbolic math programs do not do trig simplifications as well as a good math student after taking a trig class.

Analogous to the block diagrams in Faust, one needs a canonical form for every trig expression, over which "rewriting rules" (such as trigexpand() followed by trigsimp() in Maxima) are passed in order to apply simplifications such as cos^2 + sin^2 = 1. A problem is that the best final form is not obtainable using a fixed sequence of manipulations (in my past experience). It was necessary to choose the right fork in the road at the right point to get best results. I don't know if this situation has improved, but I doubt it. Maybe nowadays the right approach is to take all forks (a la Yogi Berra) and return the best result.

For some examples, see

http://maxima.sourceforge.net/docs/tutorial/en/gaertner-tutorial-revision/Pages/TrigTrans0001.htm

In principle, maxima could be integrated into Faust as a kind of "preprocessor", or some API could connect them.

On Mon, Jul 3, 2017 at 8:57 AM, sekisushai notifications@github.com wrote:

Hello,

I'm posting this issue -more as an feature request- about trigonometric simplifications.

For some applications, I manipulate trigonometric functions (spherical harmonics) and depending on the algorithm, the output formula could be very complicated.

However, in a lot of cases, trigonometric identities could help to simplify drastically the expressions.

For example, as pointed in this issue: https://github.com/grame-cncm/faust/issues/56 http://url, the algorithm outputs a matrix where all terms are functions which can be simplified in the majority of the cases. However, the output terms are not given in their simplest form, so far. For example, the term rot(2,1,1) in the algorithm described in the aforementioned issue gives:

rot(2,1,1) = cos(pitch)^2cos(roll)cos(yaw) + sin(pitch)(-cos(roll)cos(yaw)sin(pitch) + sin(roll)sin(yaw))

Which, after factorization gives rot(2,1,1) = cos(roll)cos(yaw)(cos(pitch)^2 - sin(pitch)^2)) + sin(pitch)sin(roll)sin(yaw) This latter expression is the output proposed by the compiler.

However, knowing that cos(pitch)^2 - sin(pitch)^2 = cos(2pitch) the previous expression could be simplified with: rot(2,1,1) = cos(roll)cos(yaw)cos(2pitch) + sin(pitch)sin(roll)sin(yaw) which is a simpler expression.

Following this example, I'm wondering if it is possible for the compiler to recognize trigonometric identities, typically as given in the following link: https://www.mathportal.org/formulas/pdf/trigonometry-formulas.pdf http://url

Thank you ! Pierre

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faust/issues/59, or mute the thread https://github.com/notifications/unsubscribe-auth/ACGVFcWWfy34Io2xEK3kIHq4vE4VddGuks5sKQF2gaJpZM4OMZF- .

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/ http://ccrma.stanford.edu/

cbix commented 4 years ago

Picking up this old issue, I second the idea of more advanced term rewriting for mathematical expressions. The extent to which you can do static optimization is one of the things I really like about functional language compilers and Faust use cases often require optimization of CPU cycles.

One particular thing I needed was the simplification of exp(log(x)) (resp. pow(a, log10(x))) so I can normalize a frequency parameter given in Hz for va.moogLadder without having to worry about precision loss and unnecessary calculations. But I can imagine other use cases that would benefit from this.