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.