On 22 November 2014 at 12:34, Ondřej Čertík <ondrej.cer...@gmail.com> wrote:
> On Sat, Nov 22, 2014 at 7:23 AM, Bill Page <bill.p...@newsynthesis.org> wrote:
>> ...
>> 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?

Sorry, I gave you the wrong impression. I specifically referred to the
lack of "symbolic 'conjugate operator".  By that I meant that the
'Expression' functor does not export a 'conjugate' operator.  My patch
adds such an operator to Expression.  But FriCAS has many domains of
computation besides those constructed by 'Expression' and some of them
do include 'conjugate'. For example the 'Complex' functor includes
'conjugate' so we can write:

(1) -> x:Complex Expression Integer := a + %i*b

   (1)  a + b %i
                                           Type: Complex(Expression(Integer))
(2) -> conjugate(x)

   (2)  a - b %i
                                           Type: Complex(Expression(Integer))

This effectively and implicitly treats symbols as real valued.

(3) -> D(x,a)

   (3)  1
                                           Type: Complex(Expression(Integer))
(4) -> D(x,b)

   (4)  %i
                                           Type: Complex(Expression(Integer))
(5) -> y:=log(x)

             2    2
        log(b  + a )                b
   (5)  ------------ + 2atan(--------------)%i
              2               +-------+
                              | 2    2
                             \|b  + a   + a
                                           Type: Complex(Expression(Integer))
(6) -> conjugate(y)

             2    2
        log(b  + a )                b
   (6)  ------------ - 2atan(--------------)%i
              2               +-------+
                              | 2    2
                             \|b  + a   + a
                                           Type: Complex(Expression(Integer))

But not this:

(7) -> D(y,x)
...
   Cannot find a definition or applicable library operation named D
      with argument type(s)
                        Complex(Expression(Integer))
                        Complex(Expression(Integer))

So there is no "complex derivative" as such.

We can also define things this way:

(8) -> z:Expression Complex Integer := a + %i*b

   (8)  %i b + a
                                           Type: Expression(Complex(Integer))
(9) -> D(z,a)

   (9)  1
                                           Type: Expression(Complex(Integer))
(10) -> D(z,b)

   (10)  %i
                                           Type: Expression(Complex(Integer))
(11) -> w:=log(z)

   (11)  log(%i b + a)
                                           Type: Expression(Complex(Integer))

But now we get:

(12) -> conjugate(z)
 ...
   Cannot find a definition or applicable library operation named
      conjugate with argument type(s)
                        Expression(Complex(Integer))

      Perhaps you should use "@" to indicate the required return type,
      or "$" to specify which version of the function you need.

(13) -> D(w,z)
...
   Cannot find a definition or applicable library operation named D
      with argument type(s)
                        Expression(Complex(Integer))
                        Expression(Complex(Integer))

The FriCAS 'Expression' functor extends multivariate rational
functions over a specified domain with a large number of
transcendental kernels (symbolic functions) as well as differentiation
and integration operators.  No explicit assumption is made about the
domain of the variables.  My proposed patch to FriCAS adds 'conjugate'
as another kernel function and provides a 'conjugate' as an operator.

> In SymPy and Sage, conjugate(x) is in it, so then adding a derivative
> of abs(x) does not make things worse.
>

In FriCAS 'abs' is already a kernel function and it implemented the
derivative of 'abs' even before my proposed patch but I think the
current definition is wrong:

(14) -> D(abs(x),x)

         abs(x)
   (14)  ------
            x
                                                    Type: Expression(Integer)


>>
>> 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.
>> ...
>> 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.

I would not say that they are the same "number".  Also I don't want to
define log(z) the way to suggest.  Rather, I think the correct
definition of 'log(z)' is the solution of

  z = exp(?)

So we can write z=exp(log(z)) by definition. This is exactly analogous
to the treatment of 'sqrt(z)' as the solution to

  z = ? * ?

> 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.

We do not need an extra term.  We only need axioms for the correct
behavior of the expression 'log(z)'. But 'log(z)' does not denote a
function in the sense of a many-to-one mapping.  The inverse of a
function is only a function (possibly partial) if the function is
injective (one-to-one).

> 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 Riemann surface is an important tool in complex analysis but I
have yet to see it used explicitly in any computer algebra system as a
representation of complex functions.

>
> 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.
>

In order to numerically evaluate a symbolic expression it is indeed
necessary to choose a branch in the case of "multi-valued functions",
i.e. expressions like 'sqrt(x)' and 'log(x)'.  But this choice should
not effect the axiomatic properties of these expressions.

> 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))
>
> Bill, why don't you check if FriCAS is using approach (A) or (B)?

In FrCAS we have

(2) -> normalize(log(a*b)-log(a)-log(b))

   (2)  0
                                                    Type: Expression(Integer)

and with my proposed patch we also have 'conjugate(log(z)) =
log(conjugate(z))' by definition. So this is like your (A).

>
> 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.
>

For numeric domains which support 'conjugate' FriCAS behaves in the
same way (B) as Python and the other languages you mentioned.  For
example:

(3) -> z:Complex Float := 1 - %i

   (3)  1.0 - %i
                                                         Type: Complex(Float)
(4) -> test( conjugate(log(z)) = log(conjugate(z)) -
2*%pi*%i*floor((argument(z)+%pi)/(2*%pi)) )

   (4)  true
                                                                Type: Boolean
(5) -> a:Complex Float := -1

   (5)  - 1.0
                                                         Type: Complex(Float)
(6) -> b:Complex Float := -2

   (6)  - 2.0
                                                         Type: Complex(Float)
(7) -> test( log(a*b) = log(a)+log(b) +
2*%pi*%i*floor((%pi-argument(a)-argument(b))/(2*%pi)) )

   (7)  true
                                                                Type: Boolean

Now I am a little unclear on what you are proposing.  Are you
suggesting that symbolic computations (such as those using
'Expression' in FriCAS) should somehow introduce an independent
'argument' function instead of defining it as

  argument(x) = log(x/abs(x))/%i

or that 'abs' is somehow an important part of these equalities?  Note
that 'normalize' does not have to introduce these sort of terms to in
order to return 0 in result  (2) above.

Bill.

-- 
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