On Sat, Nov 22, 2014 at 7:23 AM, Bill Page <bill.p...@newsynthesis.org> wrote:
> On 21 November 2014 at 20:18, Ondřej Čertík <ondrej.cer...@gmail.com> wrote:
>>
>> I am still confused about one thing: is this issue is already
>> present in FriCAS before your changes? Because you can
>> already use conjugate, sin, +, *, ..., even without defining the
>> derivative for abs(x). I fail to see how defining the abs(x).diff(x)
>> in the way you did it  can introduce issues that weren't present
>> in the first place.
>>
>
> FriCAS currently does not implement a symbolic 'conjugate' operator.
> The issue concerns whether adding 'conjugate' is a good idea and only
> secondly how to differentiate it.

Ah, I had no idea that FriCAS does not implement conjugate(x). How do
you handle complex numbers then?
In SymPy and Sage, conjugate(x) is in it, so then adding a derivative
of abs(x) does not make things worse.

>
>> -----
>>
>> I have finished the writeup, it starts here (you might want to refresh
>> your browser to see the latest changes):
>>
>> http://www.theoretical-physics.net/dev/math/complex.html#complex-conjugate
>>
>> and it was implemented with these two PRs:
>>
>> https://github.com/certik/theoretical-physics/pull/39
>> https://github.com/certik/theoretical-physics/pull/40
>>
>
> Thanks.
>
>> I must say one thing that I like about the "theta" is that it tells
>> you immediately if the function is analytic or not (if theta is
>> present it is not, if it is not present, then the expression does not
>> depend on theta, and thus is analytic). For example, for log(z),
>> the theta cancels, and so the result 1/z is analytic.
>>
>
> Still looks ugly to me.
>
>> I found a bug in these results from FriCAS:
>>
>>> (4) -> D(abs(f(x)),x)
>>>
>>>              , _      _  ,
>>>         f(x)f (x) + f(x)f (x)
>>>
>>>    (4)  ---------------------
>>>               2abs(f(x))
>>>                                                     Type:
>>> Expression(Integer)
>>> (5) -> D(abs(log(x)),x)
>>>
>>>         _    _
>>>         xlog(x) + x log(x)
>>>    (5)  ------------------
>>>             _
>>>           2xxabs(log(x))
>>>                                                     Type:
>>> Expression(Integer)
>>
>> The bar must be over the whole f(x) as well as log(x), because
>> conjugate(log(x)) is only equal log(conjugate(x)) if x is not
>> negative real number.
>
> In FriCAS with my patch functions defined by
>
>   f := operator 'f
>
> are currently assume to be holomorphic and log is holomorphic by definition so
>
> conjugate(log(x)) = log(conjugate(x))
>
> Perhaps you are considering the wrong branch.
>
>> See the example here:
>> http://www.theoretical-physics.net/dev/math/complex.html#id1 where I
>> have it explicitly worked out. You can also check that easily in
>> Python:
>>
>> In [1]: from cmath import log
>>
>> In [2]: x = -1+1j
>>
>> In [3]: log(x).conjugate()
>> Out[3]: (0.34657359027997264-2.356194490192345j)
>>
>> In [4]: log(x.conjugate())
>> Out[4]: (0.34657359027997264-2.356194490192345j)
>>
>> In [5]: x = -1
>>
>> In [6]: log(x).conjugate()
>> Out[6]: -3.141592653589793j
>>
>> In [7]: log(x.conjugate())
>> Out[7]: 3.141592653589793j
>>
>> In [8]: log(x.conjugate()) - 2*pi*1j
>> Out[8]: -3.141592653589793j
>>
>>
>> Where [3] and [4] are equal, but [6] and [7] are not (you need to
>> subtract 2*pi*i from [7], as in [8], in order to recover [6],
>> consistent with the formula in the writeup).
>>
>
> Complex 'log' is a multi-valued like 'sqrt' so you need to consider
> more than one branch.

Well, you are right that in theory you define log(z) as
log(z)=log|z|+i*arg(z), and you define arg(z) as multivalued, i.e. you
can add 2*pi*n to it, then you can add 2*pi*i*n to log(z). Since [6]
and [7] differs by 2*pi*i, they are indeed the same number.
However, this definition quickly becomes impractical, because you need
to be able to numerically evaluate symbolic expressions, and you would
need to carry the symbolic term 2*pi*i*n around. This multivalued
approach has always been very confusing to me. But it is a valid
approach (i.e. see http://en.wikipedia.org/wiki/Riemann_surface), so
let's call this is an approach (A).

The other approach, let's call it approach (B), is that languages like
Fortran, C, Python, and CAS like Mathematica, SymPy, Sage all pick a
branch cut, and all of them (as far as I know) pick it along the
negative real axis. For this example I think it doesn't matter where
you choose the branch cut, as the conjugate of log(-1) simply flips
the sign of it, so it won't be equal to log(-1) anymore. In this
approach you need to carry the corrections for branch cuts.

Some examples of identities valid in each approach:

(A) conjugate(log(z)) = log(conjugate(z))
(B) conjugate(log(z)) = log(conjugate(z)) -2*pi*i*floor((arg(z)+pi)/(2*pi))

or

(A) log(a*b) = log(a) + log(b)
(B) log(a*b) = log(a) + log(b) + 2*pi*i*floor((pi-arg(a)-arg(b))/(2*pi))

And so on. I have written a Python script to check many of these
identities in (B), available here:

http://www.theoretical-physics.net/dev/math/complex.html#testing-identities-using-computer-code

and it works like a charm, i.e. those identities are valid for any
complex numbers. On that page, I have also derived those identities
step by step, i.e. you simply define arg(z) = atan2(Im z, Re z) and go
from there, the floor() function comes from properties of the atan2()
function.

I don't think you can mix and match (A) with (B). You have to make a
decision and be consistent everywhere.

Bill, why don't you check if FriCAS is using approach (A) or (B)? This
is very simple to do, simply check the left hand side and right hand
side of any of these identities in (A). Since as you said, FriCAS
doesn't support conjugate(), just use the log(a*b) case. Here is how
you can check this in Python:

>>> from cmath import log
>>> a = -1
>>> b = -1
>>> log(a*b)
0j
>>> log(a)+log(b)
6.283185307179586j

So you can see that the left hand side log(a*b) does not equal the
right hand side log(a)+log(b), so Python is using the approach (B).
You can see the script above, where I check this, but for clarity,
let's just verify that the (B) formula works in Python for this
particular case:

>>> def arg(x): return log(x).imag
...
>>> from math import floor, pi
>>> I = 1j
>>> log(a)+log(b)+2*pi*I*floor((pi-arg(a)-arg(b))/(2*pi))
0j



I would assume that FriCAS is also using the approach (B), and thus
conjugate(log(z)) is not equal to log(conjugate(z)), but let's wait
until what you find.

Ondrej

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to