Skip to content

Conversation

oostben
Copy link
Contributor

@oostben oostben commented Apr 25, 2021

References to other Issues or PRs
Fixes #21365

Brief description of what is fixed or changed

  • Implemented _eval_expand_trig method for tanh funciton. expand_trig now works to expand tanh in a few different ways.
  • tanh(coeff*x) will be expanded to coeff*tanh(x).
  • tanh now detects double and half angle formulas, so if coeff is 2 or .5, it will be expanded according to the following formulas:
    • tanh Half Angle Formula: tanh(.5*x) = (cosh(x)-1)/sinh(x)
    • tanh Double Angle Formula: tanh(2x) = 2*tanh(x)/(1+tanh^2(x))
  • _eval_expand_trig also expands tanh(x+y) using the sum of arguments identity.
    • tanh Sum of Arguments Identity: tanh(x+y) = (tanh(x)+tanh(y))/(1+tanh(x)*tanh(y))

Release Notes

  • functions
    • Add _eval_expand_trig method for tanh.

Example:

>>> from sympy import *
>>> x = Symbol('x')
>>> y = Symbol('y')

>>> expand_trig(tanh(x + y))
(tanh(x) + tanh(y))/(tanh(x)*tanh(y) + 1)

>>> expand_trig(tanh(2*x))
2*tanh(x)/(tanh(x)**2 + 1)

>>> expand_trig(tanh(3*x))
3*tanh(x)

>>> expand_trig(tanh(y*x))
tanh(x*y)

>>> expand_trig(tanh((1/2)*x))
(cosh(x) - 1)/sinh(x)

expand_trig now works to expand tanh. tanh(coeff*x) will be
expanded to coeff*tanh(x). Additionally, tanh now detects
double and half angle formulas, so if coeff is 2 or .5,
it will be epanded into the formulas below.

tanh half angle formula:
tanh(.5*x) = (cosh(x)-1)/sinh(x)

tanh double angle formula:
tanh(2x) = 2*tanh(x)/(1+tanh^2(x))

Finally _eval_expand_trig also expands tanh(x+y) using the
sum of arguments identity below.

tanh(x+y) = (tanh(x)+tanh(y))/(1+tanh(x)*tanh(y))

Example:

>>> from sympy import *
>>> x = Symbol('x')
>>> y = Symbol('y')

>>> expand_trig(tanh(x + y))
(tanh(x) + tanh(y))/(tanh(x)*tanh(y) + 1)

>>> expand_trig(tanh(2*x))
2*tanh(x)/(tanh(x)**2 + 1)

>>> expand_trig(tanh(3*x))
3*tanh(x)

>>> expand_trig(tanh(y*x))
tanh(x*y)

>>> expand_trig(tanh((1/2)*x))
(cosh(x) - 1)/sinh(x)
@sympy-bot
Copy link

sympy-bot commented Apr 25, 2021

Hi, I am the SymPy bot (v161). I'm here to help you write a release notes entry. Please read the guide on how to write release notes.

Your release notes are in good order.

Here is what the release notes will look like:

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.9.

Click here to see the pull request description that was parsed.
**References to other Issues or PRs**
Fixes #21365

**Brief description of what is fixed or changed**
- Implemented _eval_expand_trig  method for tanh funciton. expand_trig now works to expand tanh in a few different ways.
- tanh(coeff*x) will be expanded to coeff\*tanh(x).
- tanh now detects double and half angle formulas, so if coeff is 2 or .5, it will be expanded according to the following formulas:
    - tanh Half Angle Formula: **tanh(.5\*x) = (cosh(x)-1)/sinh(x)**
    - tanh Double Angle Formula: **tanh(2x) = 2\*tanh(x)/(1+tanh^2(x))**
- _eval_expand_trig also expands tanh(x+y) using the sum of arguments identity.
    - tanh Sum of Arguments Identity: **tanh(x+y) = (tanh(x)+tanh(y))/(1+tanh(x)\*tanh(y))**

**Release Notes**
<!-- BEGIN RELEASE NOTES -->
* functions
  * Add _eval_expand_trig method for tanh. 
<!-- END RELEASE NOTES -->

Example:
```
>>> from sympy import *
>>> x = Symbol('x')
>>> y = Symbol('y')

>>> expand_trig(tanh(x + y))
(tanh(x) + tanh(y))/(tanh(x)*tanh(y) + 1)

>>> expand_trig(tanh(2*x))
2*tanh(x)/(tanh(x)**2 + 1)

>>> expand_trig(tanh(3*x))
3*tanh(x)

>>> expand_trig(tanh(y*x))
tanh(x*y)

>>> expand_trig(tanh((1/2)*x))
(cosh(x) - 1)/sinh(x)
```

Update

The release notes on the wiki have been updated.

oostben added 2 commits April 26, 2021 07:51
-removed unused code: *(1)**((i % 4)//2)
-cleaned up logic accordingly
@oostben
Copy link
Contributor Author

oostben commented Apr 26, 2021

I was able to generalize the tanh(coeff*x) case using this formula:

Screen Shot 2021-04-26 at 8 52 47 AM

I also removed the pointless multiplication pointed out in the review.

@sylee957
Copy link
Member

Does this also work with n-ary addition?
(e.g. expand_trig(tan(x+y+z)) -> (-tan(x)*tan(y)*tan(z) + tan(x) + tan(y) + tan(z))/(-tan(x)*tan(y) - tan(x)*tan(z) - tan(y)*tan(z) + 1))

@oostben
Copy link
Contributor Author

oostben commented Apr 28, 2021

Yes it does work with n-ary addition.

>>> from sympy import *
>>> w = Symbol('w')
>>> x = Symbol('x')
>>> y = Symbol('y')
>>> z = Symbol('z')
>>> expand_trig(tanh(x+y+z))
(tanh(x)*tanh(y)*tanh(z) + tanh(x) + tanh(y) + tanh(z))/(tanh(x)*tanh(y) + tanh(x)*tanh(z) + tanh(y)*tanh(z) + 1)
>>> expand_trig(tanh(x+x+x))
(tanh(x)**3 + 3*tanh(x))/(3*tanh(x)**2 + 1)
>>> expand_trig(tanh(3*x))
(tanh(x)**3 + 3*tanh(x))/(3*tanh(x)**2 + 1)
>>> expand_trig(tanh(x+y))
(tanh(x) + tanh(y))/(tanh(x)*tanh(y) + 1)
>>> expand_trig(tanh(x-y))
(tanh(x) - tanh(y))/(-tanh(x)*tanh(y) + 1)
>>> expand_trig(tanh((1/2)*x))
(cosh(x) - 1)/sinh(x)
>>> expand_trig(tanh(4*x))
(4*tanh(x)**3 + 4*tanh(x))/(tanh(x)**4 + 6*tanh(x)**2 + 1)
>>> expand_trig(tanh(w+x+y+z))
(tanh(w)*tanh(x)*tanh(y) + tanh(w)*tanh(x)*tanh(z) + tanh(w)*tanh(y)*tanh(z) + tanh(w) + tanh(x)*tanh(y)*tanh(z) + tanh(x) + tanh(y) + tanh(z))/(tanh(w)*tanh(x)*tanh(y)*tanh(z) + tanh(w)*tanh(x) + tanh(w)*tanh(y) + tanh(w)*tanh(z) + tanh(x)*tanh(y) + tanh(x)*tanh(z) + tanh(y)*tanh(z) + 1)

@sylee957
Copy link
Member

Half angle formula wasn't used for expanding tan.
I'm not sure if this can be added later, but at least I think that it's better to align the behaviors

@sylee957
Copy link
Member

This may need some tests at test_trigonometric.py

@smichr
Copy link
Member

smichr commented May 1, 2021

OP could be updated to reflect that half angle recognition is not included.

@smichr
Copy link
Member

smichr commented May 1, 2021

I wonder if expand_trig (or user?) should just be using the conversions from hyperbolic to regular trig functions ala fu.hyper_as_trig. I also see that the tan._eval_trig has real and imaginary handling -- is this not needed for hyperbolic tanh?

@smichr
Copy link
Member

smichr commented May 2, 2021

The unconditional else will cause integer arguments to expand in terms of tanh(1) -- I'm not sure that is helpful. Someone can replace int args with int*Symbol('1') and expand to see that result if they want.

tanh(5), tanh(5*Symbol('1')) -> (tanh(1)**5 + 5*tanh(1) + 10*tanh(1)**3)/(1 + 5*tanh(1)**4 + 10*tanh(1)**2)

@jksuom
Copy link
Member

jksuom commented May 2, 2021

is this not needed for hyperbolic tanh?

The imaginary unit I appears in the formulas for tan because of Euler's formula

    cos(x) + I*sin(x) = exp(I*x).

It could be avoided by elementary plane trigonometric arguments but it simplifies the mathematics.

I is not needed for computations with tanh since it does not appear in 'hyperbolic Euler's formula'

    cosh(x) + sinh(x) = exp(x).

@oostben
Copy link
Contributor Author

oostben commented May 5, 2021

Is there anything else that needs to be done for this PR to be merged?

Should I add some tests for this anywhere?

Where would I note that half angle recognition is not included @smichr?

@smichr
Copy link
Member

smichr commented May 5, 2021

Is there anything else that needs to be done for this PR to be merged?

please address this comment

… treated as such. If argument is not addition or multiplication, original argument is returned.
@oostben
Copy link
Contributor Author

oostben commented May 6, 2021

Originally we had this with the unconditional else:

expand_trig(tanh(5)) -> (tanh(1)**5 + 5*tanh(1) + 10*tanh(1)**3)/(1 + 5*tanh(1)**4 + 10*tanh(1)**2)
expand_trig(tanh(5*Symbol('1'))) -> (tanh(1)**5 + 10*tanh(1)**3 + 5*tanh(1))/(5*tanh(1)**4 + 10*tanh(1)**2 + 1)

After making the unconditional else into:
elif arg.is_Mul:

I get:
expand_trig(tanh(5)) -> tanh(5)
expand_trig(tanh(5*Symbol('1'))) -> (tanh(1)**5 + 10*tanh(1)**3 + 5*tanh(1))/(5*tanh(1)**4 + 10*tanh(1)**2 + 1)

Also I wanted to note that the reason, I made that else unconditional was because that is how it's done in tan's _eval_expand_trig method:

expand_trig(tan(5)) -> (-10*tan(1)**3 + 5*tan(1) + tan(1)**5)/(-10*tan(1)**2 + 1 + 5*tan(1)**4)

However, I agree that it doesn't make sense to treat all expansions as multiplications if they are not additions. Might be something to change in tan's _eval_expand_trig to keep the behavior standard.

Is this the type of fix you were looking for?

@smichr
Copy link
Member

smichr commented May 6, 2021

Is this the type of fix you were looking for?

yes -- I am not an expert in trig expression wrangling, but the expansion doesn't seem profitable (and the user can use the symbolic number to expand a certain factor of the numeric arg if they desire, e.g. tan(4) = tan(2*Symbol('2')))

I think it would be ok to make this change in the regular tan expansion, too.

@smichr
Copy link
Member

smichr commented May 6, 2021

ok to make this change in the regular tan expansion, too.

Are you willing to do that? If so, I'll wait until that change is present before starting tests.

@oostben
Copy link
Contributor Author

oostben commented May 8, 2021

@smichr I added the change to all the trig functions in #21440 because they all share the same behavior.

@smichr smichr merged commit 572710e into sympy:master May 19, 2021
@smichr
Copy link
Member

smichr commented May 19, 2021

This is in, thanks. Will watch for #21440 to finish up, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

expand_trig does not work with tanh
6 participants