> Can you solve this equation for x? > > x log(kx) = (x - 1)log(1 - x) > > the answer might involve Lambert's W function, but I'm not sure It's not solved for x, but it looks nice this way... > log(k)=Int(1+log(s),s=1/x-1 .. 1/x); 1/x / | ln(k) = | ln(s) + 1 ds | / 1/x - 1 ==== >> In what general systems are you thinking? Are you saying that there are >> some systems where solving is easier than simplification or just not >> -much- worse (i.e. the same complexity). > > The paper below, by Daniel Richardson proves that the task tell me if > this expression is zero or not is undecidable. The expression class > is necessarily broader than polynomials, for which the decision problem > is easily solvable. > > Daniel Richardson: Some Undecidable Problems Involving Elementary > Functions of a Real Variable. J. Symb. Log. 33(4): 514-520 (1968). Solving whatever that means --- is not going to be harder. Do you mean not harder than undecidable? I see you point if you take that to be a ceiling (in the universe of problems, almost all are undecidable). But there is a hierarchy of undecidablility (suppose, contrary to reality, that you have an oracle for a particular undecidable problem; some previously undecidable problems are now decidable, but some still are not). I take solving to be determining the member or members of the domain that, when substituted into the formula, make it true, that is a satisfying valuation. simplification for me is creating a new formula that has the same solutions, but is canonical (smallest) in some given ordering (so I suppose the ordering is a hidden parameter to the problem). I suppose that if all variables are eliminable and eliminated in the simplification process, then -that- is a solution. And I see that it is very plausible that simplification can be reduced to solving (if you have a solution then -that- is your simplified form). So are you saying in your experience these two processes are usually interreducible (as opposed to the poly simplification/poly solution case)? Mitch ==== > > > Do you mean not harder than undecidable? I see you point if you take > that to be a ceiling (in the universe of problems, almost all are > undecidable). But there is a hierarchy of undecidablility (suppose, > contrary to reality, that you have an oracle for a particular > undecidable problem; some previously undecidable problems are now > decidable, but some still are not). > I think this is interesting. If you have an oracle Q that can tell you is this expression in the variable x identically zero then you (with some additional conditions) have a perfect simplifier. The condition is that you are able to generate, in order of simpler to complicated, all legal expressions in your class, a[0], a[1], .... . and you can substract... In order to simplify the expression E, just run for i:=0 to infinity do if Q(E-a[i]) then return(a[i]). The simplest expression equivalent to E is the answer. You might be able to do the same thing for solve, assuming you have a procedure that will plug the answer in and check is this a solution? Of course for solve it may be that no answer in your class of expressions is a solution and so you will never terminate. You can apply this reasoning to the polynomial situation, but for polynomial simplification you can do much better! RJF ==== > [...] > Hence my preference to C++ over C because you can overlad > arithmetic operator (I'm not sure but I believe you can't > in java, > > There are other ways of doing extensions in Java, which I am > sure Java advocates will be happy to explain. Normally there are no extensions in java, in the sense of changes that affect the grammar. This makes it simple and readable, but as a consequence arithmetic operator overload can't be implemented. There is an exception though : the grammar can change with new versions, and precisely, with jdk1.5, there will be autoboxing, which enables using the arithmetic operators with reference types like Integer, Long, Double etc. However this feature will be limited to these build-in wrapper types, so with no application in computer algebra. ==== .. notation for GCD >> No, I think the usual notation in mathematics is (b,c). >> see Van der Waerden, Algebra (vol 2) section 15.2 p 119. >> (my copy is (c) 1970). > > I have never seen this notation for gcd. Sometimes ^ is used > but most of the time the prefix notation. I just looked in a second algebra book on my shelf, Birkhoff and MacLane, A Brief Survey of Modern Algebra. Page 17. In fact it say of the two possible g.c.d.'s +-d for a and b, the positive one is often denoted by the symbol . (a , b) ... And here is another place.. http://mathworld.wolfram.com/GreatestCommonDivisor.html > >> Furthermore, mathematics typically has no assignment operation, >> and the meaning of the mathematics notation a=b is ambiguous. It >> certainly does not mean what any of the assignment statements above >> mean... thus a notation like x=x+1 is on the face of it absurd. >> What does = mean in mathematics? >> It could be a statement like 1+1=2, of a fact. >> It could be a relation like sin(x)=y to be converted to some other >> relation by solve for x. >> It could be a FALSE hypothesis, such as suppose a^2+b^2=c^2. >> It could be a definition (though often a different notation is used >> for this.) > > Mathematicians use the = notation and the meaning is clear from > the context. Since programmers rarely have the full context of the mathematics, it seems to me to be better not to use =. Lisp has setf for assignment = for numeric equality eq for identical equal addresses equal for list structure eql ... > >> Mathematics does not use * for multiplication. a*b might mean >> almost anything. transpose(a)? conjugate(a), Kleene star? > > Ask anyone who used a calculator what * means, you will get > the answer: * clearly means multiplication. My calculator has an X on it, not an asterisk (*). > > For the same reason, I prefer to write > a=1/(b+c*d) > than say a=gdiv(1,gadd(b,gmul(c,d))) >> I do not know what your statement means. Does division mean an >> operation in a field, or division in a ring? e.g. >> 12/3 --> 4 is valid in a ring, so division sometimes works. >> 12/5 --> not a ring element, so it sometimes doesn't work. >> In the rational field, >> (12/1) / (3/1) --> (4/1) >> (12/1) / (5/1) --> (12/5) so this is OK. >> Without knowing which / you mean your program may be >> erroneous, or sloppy. A generic division doesn't work! > > Come back in the world of mortals. Ask anyone what / means > he will answer division. I of course assume we have a C++ > generic type (like GEN in pari, gen in giac, ex in GiNaC, ...). > >> If you prefer to write lisp in infix, there are several widely >> available infix notation packages that allow you to do something like >> (setf a #.[1/(b+c*d)]) >> or even #.[ a:=1/(b+c*d)] but of course this assumes you mean >> to use the operations as given. > > remove the #.[ ] and I'll be happy. > >> I do not find the infix operations helpful in expressions like this one, >> from a paper of mine... >> (* (+ (* x (+ (* x (+ (* w (+ -1.745986568814345d0 w z)) >> 1.213871280862968d0)) >> 9.4939615625424d0)) >> -94.9729157094598d0) >> -0.00420059d0) > >> - 0.00420059d0 * (x * (x * (w * (z + w - 1.74598656881434d0) + >> 1.21387128086296d0) + 9.4939615625424d0) - 94.9729157094598d0) >> Is this better? > > > Yes (except I don't understand what 1.21387128086296d0 means), > but that's too long, it's better to have an intermediate variable > gen tmp= w * (z + w - 1.74598656881434d0) + 1.21387128086296d0; > gen result=- 0.00420059d0 * (x * (x *tmp+ 9.4939615625424d0) - > 94.9729157094598d0); That is a double precision float. 1.23d0 means 1.23 X 10^0. I do not find infix arithmetic particularly compelling, and it has the extra problem of requiring you to either understand the precedence or put in extra parentheses. > > >> There are other ways of doing extensions in Java, which I am >> sure Java advocates will be happy to explain. >> I don't know for lisp but it seems a constant of lisp > to use 5-th like notations), >> That is because they are better, not because Lisp forces >> you to use them!!! > > You claim this, but I don't see any reason why. The answer is in the next sentence: > I don't have a personal experience in Lisp, That's why. > but in reverse > polish lisp (RPL) where you use a stack and functions are > applied to their arguments on the stack and return their > arguments on the stack, for example gcd(a,b) would be > a b gcd > (i.e. the reverse of lisp, without parenthesis, which BTW > requires a fixed number of arguments for every function). > I have implemented a CAS in RPL and I'm implementing a CAS > in C++, I can tell you that it's much much easier to do it > in C++ (it would probably also be easier in Lisp than in RPL but > both languages have more in common than C++ and RPL or Lisp > hence my guess that it is in fact harder to write a CAS in Lisp > than in C++). Your assumption that RPL and Lisp have more in common than Lisp and C++ is not reasonable. You should really learn some Lisp. I suggest Paul Graham's ANSI Common Lisp. > >> I find maple code to be unreadable, partly because the typical >> way of returning values is to have one or more return value parameters >> as strings as arguments to a procedure. This makes the assignment >> of values resulting from a procedure some arbitrary distance away >> from the invocation of the procedure. > > > I don't understand what you mean. Is it that you don't > like constructions like you would have for the extended > euclidean algorithm in C > int egcd(int a,int b,int & u,int &v); Yes, that is a similar situation. In Lisp you could handle the return of some number of arguments in a variety of ways, but one is this way: (multiple-value-bind (u v) (egcd a b) ... compute with u, v ....) where egcd would look like this... (defun egcd(r s) ..... compute stuff..... (return (values c d)) ..) > >> There are also different >> rules for evaluation depending on whether you type an expression >> at the top level or call it from another procedure. > > This has nothing to do with clarity of an algorithm. It means you can't debug a function f(a,b,c) in Maple by typing in f(a,b,c). You must write a procedure to call it if you want the same semantics. > >> C++ is generally used as a batch language, and from my perspective, >> this makes it almost inconceivable that anyone familiar with an >> interactive language would use ANY batch language for complex >> prototyping and experimentation. > > I don't see why. As I said each language has its good points > and weak points. I would probably use an interactive language for > a quick test without much programming, but not for a complex task > with many subroutines. Why would you not use an interactive language for a complex task? > > I don't believe there is *a* language more appropriate than others. > The best would be of course to have all these languages > be able to talk one to each other in an almost transparent way. >> Maybe not. If you had to make uncomfortable adaptations, you >> might not want this. Say someone said, let's all use Microsoft .net. >> Would that be best? > > I was probably not clear enough. I meant in an ideal world, > you could use your prefered language and have full access to > all the packages developped using other languages. And everything > would run on every platform. Unfortunately, we are not living > in this world. So you have to choose a language and the decision > will be based on many factors. For me, using a language that > is widely used by the open source community is very important > because it's reasonnably certain that 30 years from now it will > compile and run. My experience is that programs written in C require extensive re-porting to run in different environments. The use of a configure script is an example of how much effort is required to make a program in C run on every platform. Of course other programming languages may need such help, but it is simply not true that a program written in C or Java will run on an arbitrary platform. > > You have to choose depending on what you want to do exactly > and what tools are available (the first one being the compiler), > where you want to port your application, what kind of user > interface, etc. >> The major restriction is not what tools are available, but what >> tools you and your programmers know how to use. > > I don't agree. Using some C or C++ libraries is certainly > way easier from C++ than from any other language. Then consider > the amount of such libraries that can be included in a CAS. Since you seem to look at GMP as an example, can you compare the ease with which you can use GMP from Python, C++, Perl, Ruby, Java, Lisp? Actually, I suspect that the obvious interface between C and GMP leaks memory. > > In the case of someone who knows C and want to write a program > to compute GCD of polynomials of small degree with integer > coefficients, learning the C++ vector to represent polynomials > and using GMP (mpz_class) for the coefficients and implementing > gcdheu requires probably around 2 weeks. >> If you want to do any sequence of calculations with polynomials >> that produces intermediate expressions, you need to also write >> storage management. > > No, mpz_class and vector do the storage management, you can use > them like a fixed-length data type in a C++ program. If you have variables which point to mpz (gnu multiple-precision integers), how do you know when the numbers can be erased? Perhaps you are assuming no shared values, in which case an assignment a=b must become mpz_deallocate(a); a=mpz_copy(b). This is not a very good plan. Allocating storage is easy. Deallocating storage is harder to do correctly. > Obviously, * should return (x+1)*(x-1), because the first form > requires simplification that the programmer should explicitely > write (e.g. a=normal(b*c);) >> so you are saying that 3*4 should return the tree for 3*4, and to >> get the result 12 you need to write normal(3*4) ? > > > Of course not. The * operator will check the argument > types and do the operations on integers. It should return > what you expect it to return. I claim that (x+1) times (x-1) > should return the tree (x+1)*(x-1) and not x^2-1 because > the second form requires a relatively complex operation, > as 4 times 3 should return 12 because it's a simple operation. Simple? is a product of two big numbers simple or not? A call to a GMP routine? How about two rational numbers? Two complex numbers whose real and imaginary parts are huge rational numbers? Does a/b rationalize the denominator for complex a,b? > >> I might want >> to create a tree that looks like this: factors_of_12 = 2*2*3. >> What * do I use then? > > You must do something more (i.e. quote the * operation), > because one expects 2*2*3 to return 12. Oh, so what is the point of the overloaded * operation? Now you must do something like create_tree(*,create_tree(*,2),2),3). So some of the operations you claim can be done with overloaded C++ operations don't work that way. > > I don't have time for this. Just look around and see how CAS > are implemented, the answer is that there is not a prefered > language. >> The subject line says which is best. I know that there are a variety of opinions. I am hoping for some way of testing. A survey of opinions is not testing! >> On the same basis, the most appropriate operating system for a >> desktop computer is something sold by Microsoft. Not convincing >> to me! > > I did not speak of the most popular CAS, I spoke of how CAS are > Solaris, HP-UX, FreeBSD to your comparision. > >> How far advanced would Maple and Mathematica be today if they didn't >> have to debug their C code, if they didn't have to figure out how >> they were leaking memory, etc. > > You probably mean how far would they be if they had choosen Lisp? > We will never know! My guess is they would not be as good, > simply because the people who use C-like languages outperforms > the number of people who use Lisp-like languages and the percentage > of good programmers is probably not very different in any language. I am not sure I can parse your statement. If you are saying that there are more C programmers than Lisp programmers, that is true. If you say that they are equally productive, the only (limited) evidence I have seen is that some Lisp programmers are very productive, and attempts to compare them to C programmers usually ends up with Lisp being better. A search on google finds a few of these comparisons. Here's a nice essay by Paul Graham ... http://www.paulgraham.com/icad.html > >> Here is one, implicit in your note: >> Write an implementation of gcdheu for polynomials (in one variable?) >> with integer coefficients. Or do you mean .. in any number of >> variables? How long does it take? > > > Well, we have two tests here: > one variable and any number of variables > Any other tests? ==== My experience is that programs written in C require extensive >re-porting to run in different environments. The use of a configure >script is an example of how much effort is required to make a >program in C run on every platform. Of course other programming >languages may need such help, but it is simply not true that a >program written in C or Java will run on an arbitrary platform. It is pretty amazing that low level Java (without GUI) does run properly on several different platforms. It is extraordinary actually to have a CAS written in Java for JDK 1.1 running on several different PersonalJava implementations and now also running properly on J2ME CLDC/MIDP, the exact same code, nothing changed or compensated at all; One String-based engine that runs unmodified on any arbitrary Java implementation. Now the GUI on the other hard is simply chaotic and a disappointment, Java can do better and should do better. So to throw some wood in this fire, I would say that Java (for me) is a very good language to develop CAS software. Carlos. ==== > So to throw some wood in this fire, I would say that Java (for me) > is a very good language to develop CAS software. Glad to see that another CAS developer opinion reinforces my main point: depending on the application you develop, you will choose one or another language, there is no prefered language to develop a CAS. ==== I think we don't live in the same world! > I just looked in a second algebra book on my shelf, > Birkhoff and MacLane, A Brief Survey of Modern Algebra. > Page 17. In fact it say > of the two possible g.c.d.'s +-d for a and b, the > positive one is often denoted by the symbol > > . > (a , b) > > ... > > And here is another place.. > http://mathworld.wolfram.com/GreatestCommonDivisor.html > I'm a mathematician, and again I can insure you I never saw this notation before. Which means for me a couple of (integers or polynomials). Maybe it's a local US notation. >> Mathematicians use the = notation and the meaning is clear from >> the context. > > > Since programmers rarely have the full context of the mathematics, > it seems to me to be better not to use =. > Lisp has setf for assignment > = for numeric equality > eq for identical equal addresses > equal for list structure > eql ... > C uses = for assignement and == for equality, that's a reasonable choice, despite the fact that CAS users make mistakes because they write tests with =. >> Ask anyone who used a calculator what * means, you will get >> the answer: * clearly means multiplication. > > > My calculator has an X on it, not an asterisk (*). > Then buy yourself a more advanced calc that displays an history of your calculations, you will see the * in the history. >> Yes (except I don't understand what 1.21387128086296d0 means), >> but that's too long, it's better to have an intermediate variable >> gen tmp= w * (z + w - 1.74598656881434d0) + 1.21387128086296d0; >> gen result=- 0.00420059d0 * (x * (x *tmp+ 9.4939615625424d0) - >> 94.9729157094598d0); > > > That is a double precision float. 1.23d0 means 1.23 X 10^0. The standard scientific notation is e not d between mantissa and exponent, we don't live in the same world! > I do not find infix arithmetic particularly compelling, and it > has the extra problem of requiring you to either understand > the precedence or put in extra parentheses. > The precedence of + and * in e.g. a+b*c is taught during highschool. It is therefore standard notation and it is more compact than (+ a (* b c)) > That is because they are better, not because Lisp forces > you to use them!!! > You claim this, but I don't see any reason why. > > The answer is in the next sentence: > >> I don't have a personal experience in Lisp, > > > That's why. > > >> but in reverse >> polish lisp (RPL) where you use a stack and functions are >> applied to their arguments on the stack and return their >> arguments on the stack, for example gcd(a,b) would be >> a b gcd >> (i.e. the reverse of lisp, without parenthesis, which BTW >> requires a fixed number of arguments for every function). >> I have implemented a CAS in RPL and I'm implementing a CAS >> in C++, I can tell you that it's much much easier to do it >> in C++ (it would probably also be easier in Lisp than in RPL but >> both languages have more in common than C++ and RPL or Lisp >> hence my guess that it is in fact harder to write a CAS in Lisp >> than in C++). > > > Your assumption that RPL and Lisp have more in common than > Lisp and C++ is not reasonable. Regarding standard algebraic notation versus proprietary notation for arithmetic it makes plain sense. > You should really learn > some Lisp. I suggest Paul Graham's ANSI Common Lisp. > This is a constant of your arguments, you say always learn Lisp, then you will be enlightened and you will prefer Lisp. You don't give any argument why I should spend some time to do so. And since I prefer algebraic notation, I don't see any good reason to learn Lisp. >> int egcd(int a,int b,int & u,int &v); > > > Yes, that is a similar situation. > > In Lisp you could handle the return of some number of arguments > in a variety of ways, but one is this way: > > (multiple-value-bind (u v) (egcd a b) ... compute with u, v ....) > > where egcd would look like this... > > (defun egcd(r s) ..... compute stuff..... (return (values c d)) ..) > > So what? In fact the C like method allows you to modify values in u and v (not very useful for egcd, but it is very useful for example if you want to add some elements to a vector), without any copy. >> This has nothing to do with clarity of an algorithm. > > > It means you can't debug a function f(a,b,c) in Maple > by typing in f(a,b,c). You must write a procedure to call > it if you want the same semantics. > I don't understand what you mean. >> I don't see why. As I said each language has its good points >> and weak points. I would probably use an interactive language for >> a quick test without much programming, but not for a complex task >> with many subroutines. > > > Why would you not use an interactive language for a complex task? > Sorry, I didn't mean an interactive language, I meant a scripting language like Maple/Mupad/... one, which are not standardized and do not give real tools to write e.g. a 100,000 lines program. > > My experience is that programs written in C require extensive > re-porting to run in different environments. The use of a configure > script is an example of how much effort is required to make a > program in C run on every platform. Of course other programming > languages may need such help, but it is simply not true that a > program written in C or Java will run on an arbitrary platform. > If you do this from the beginning, porting to another platform is not hard, sometimes just recompilation of some libraries. > Since you seem to look at GMP as an example, can you compare the > ease with which you can use GMP from Python, C++, Perl, Ruby, Java, > Lisp? Actually, I suspect that the obvious interface between C and > GMP leaks memory. > In a C++ program, as I said in my previous message, you use it like the int type. > No, mpz_class and vector do the storage management, you can use >> them like a fixed-length data type in a C++ program. > > > If you have variables which point to mpz (gnu multiple-precision > integers), how do you know when the numbers can be erased? Perhaps > you are assuming no shared values, in which case an assignment > a=b must become mpz_deallocate(a); a=mpz_copy(b). > This is not a very good plan. > Allocating storage is easy. Deallocating storage is harder to > do correctly. > If I don't care, it will not be plain efficient, but it will work if I want to be efficient, I will use directly GMP or make myself a class around GMP to share numbers (that's exactly what I do for my C++ CAS). > > Simple? is a product of two big numbers simple or not? A call to > a GMP routine? How about two rational numbers? Two complex numbers > whose real and imaginary parts are huge rational numbers? Does > a/b rationalize the denominator for complex a,b? > Yes to all. Maybe the * operation in GMP requires advanced arithmetic to be efficient but it is a simple operation if you don't think about efficiency and is therefore expected to be done. To the contrary, there is no reason to believe that x^2-1 is better than (x+1)*(x-1), therefore multiplying x+1 by x-1 should do the minimal operation. >> You must do something more (i.e. quote the * operation), >> because one expects 2*2*3 to return 12. > > > Oh, so what is the point of the overloaded * operation? Now you > must do something like create_tree(*,create_tree(*,2),2),3). > So some of the operations you claim can be done with overloaded > C++ operations don't work that way. > In a C++ program, I will never use a tree to store the integer factor decompositions, I would use a vector. I will maybe need to do it once for display purpose in an interactive CAS session that's all. I use * many many times in my C++ code. Hence your counter-example does not prove that overloading * is not interesting. >> You probably mean how far would they be if they had choosen Lisp? >> We will never know! My guess is they would not be as good, >> simply because the people who use C-like languages outperforms >> the number of people who use Lisp-like languages and the percentage >> of good programmers is probably not very different in any language. > > > I am not sure I can parse your statement. If you are saying that > there are more C programmers than Lisp programmers, that is true. > If you say that they are equally productive, the only (limited) > evidence I have seen is that some Lisp programmers are very productive, > and attempts to compare them to C programmers usually ends up with Lisp > being better. A search on google finds a few of these comparisons. > I claim that even if there is a higher percentage of good Lisp programmers than C/C++ programmers, but the number of C/C++ programmers would more than compensate. > Here's a nice essay by Paul Graham ... > http://www.paulgraham.com/icad.html > > I'm not sure he has collected objective arguments. ==== > The precedence of + and * in e.g. a+b*c is taught during highschool. > It is therefore standard notation and it is more compact than > (+ a (* b c)) (* a b c (+ d e f)) vs a*b*c*(d+e+f) gives 12 tokens vs 13 tokens ==== > >> The precedence of + and * in e.g. a+b*c is taught during highschool. >> It is therefore standard notation and it is more compact than >> (+ a (* b c)) > > > (* a b c (+ d e f)) vs a*b*c*(d+e+f) > > gives 12 tokens vs 13 tokens > Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. <2e971b12.0312090900.23f9e599@posting.google.com> <3FD6EFEF.8060007@tcs.inf.tu-dresden.de> <2e971b12.0312100926.4d5dc400@posting.google.com> <3FD9B18C.4080907@users.ch> ==== bernar >> (* a b c (+ d e f)) vs a*b*c*(d+e+f) bernar >> bernar >> gives 12 tokens vs 13 tokens bernar >> bernar > bernar >Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. To add up n 1-digit positive numbers in LISP, it requires: 2n+3 characters. To add up n 1-digit positive numbers with infix notation, it requires: 2n-1 characters. So you 'win' by 4 characters. Woo-hoo. But with LISP, you get elegant notation. Unless you get a thrill out of explicit '+' signs all over the place, it makes much more sense to put it in front. Honestly, both C++ and LISP give you the power to build your own infix operators. But how often does one do that, rather than just building a function which can take an arbitrary number of arguments, and then distribute the operators? Honestly? Infix limits you to functions of two arguments. There's no such limitation with post- or prefix. ~Tomer ==== > > To add up n 1-digit positive numbers in LISP, it requires: > > 2n+3 characters. > > To add up n 1-digit positive numbers with infix notation, it requires: > > 2n-1 characters. > > So you 'win' by 4 characters. Woo-hoo. > Yes, and that's not negligible since n should be kept small to keep readability. Instead of long undecipherable expressions, I much prefer intermediate statements. > But with LISP, you get elegant notation. Unless you get a thrill > out of explicit '+' signs all over the place, it makes much more sense > to put it in front. > In a CAS, you are going to do arithmetic operations often, therefore I maintain that lisp notation is not as elegant as algebraic notation since algebraic notation is much more like mathematical notation. Even maxima, a CAS programmed in Lisp, uses algebraic notation for its own proprietary language. ==== > > In a CAS, you are going to do arithmetic operations > often, Perhaps surprising, this is likely to be false. CAS internal programs tend not to evaluate numerical objects, but manipulate data. Most of the arithmetic is likely to be in iterating over the index of an array. In the whole program to multiply polynomials, you probably see one occurrence of multiplication of the coefficients, and one occurrence of addition of exponents. You see much more data allocation and checking. therefore I maintain that lisp notation is not as elegant > as algebraic notation since algebraic notation is much more > like mathematical notation. Even maxima, a CAS programmed in Lisp, > uses algebraic notation for its own proprietary language. Maxima, along with most CAS, has a user command language intended to mimic mathematical notation. It is loosely based on Algol 60. For Maxima, some internal programs are written in this language (translated into Lisp automatically). It doesn't give convenient access to all aspects of the data, but sometimes that doesn't matter. It makes interfacing with Maxima evaluation and simplification more automatic, and (especially for the novice) it indeed provides very generic operations of +, *, / ... in an infix notation. I think a better example may be Maple or Mathematica each of which has large portions of its system routines written in the user language. Does that mean those languages are best for implementing a CAS? Probably not, because if that were the case, the Mathematica people would stop writing any more in C. Not the case. I don't know about Maple.. in fact they may refrain from writing in C except for user-interface stuff. Maybe someone who knows can answer. > ==== > > The precedence of + and * in e.g. a+b*c is taught during highschool. > It is therefore standard notation and it is more compact than > (+ a (* b c)) >> (* a b c (+ d e f)) vs a*b*c*(d+e+f) >> gives 12 tokens vs 13 tokens > > Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. > How much lexical analysis did you ever do ? Spaces aren't tokens. In any case, if what you mean is a measure of perceptive/cognitive load of parsing the two styles of expressions, then put a*b*c*(d+e+f) into the properly spaced, readable style, that will save the reader's nervous system from needlessly having to sort out from context, that the *'s and the +'s of the C expression shouldn't be interpreted as prefix or postfix operators. ==== The precedence of + and * in e.g. a+b*c is taught during highschool. > It is therefore standard notation and it is more compact than > (+ a (* b c)) >> (* a b c (+ d e f)) vs a*b*c*(d+e+f) >> gives 12 tokens vs 13 tokens > > Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. > How much lexical analysis did you ever do ? Spaces aren't tokens. In any case, > if what you mean is a measure of perceptive/cognitive load of parsing the two > styles of expressions, then put a*b*c*(d+e+f) into the properly spaced, > readable style, that will save the reader's nervous system from needlessly > having to sort out from context, that the *'s and the +'s of the C expression > shouldn't be interpreted as prefix or postfix operators. For the compactness argument, it seems to me 19 characters vs 13 characters as Parisse mentioned (spaces are not required in C/C++/Java whereas they are in Lisp). Carlos. ==== > > > > The precedence of + and * in e.g. a+b*c is taught during highschool. >It is therefore standard notation and it is more compact than >(+ a (* b c)) >>(* a b c (+ d e f)) vs a*b*c*(d+e+f) >>gives 12 tokens vs 13 tokens > >Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. >How much lexical analysis did you ever do ? Spaces aren't tokens. In any case, >>if what you mean is a measure of perceptive/cognitive load of parsing the two >>styles of expressions, then put a*b*c*(d+e+f) into the properly spaced, >>readable style, that will save the reader's nervous system from needlessly >>having to sort out from context, that the *'s and the +'s of the C expression >>shouldn't be interpreted as prefix or postfix operators. > > > For the compactness argument, it seems to me 19 characters vs 13 characters > as Parisse mentioned (spaces are not required in C/C++/Java whereas they > are in Lisp). If string length rather than token count was an appropriate measure of expression readability, then you shouldn't ever use identifiers longer than a character or two. Having suffered decades ago with Wang Basic that only allowed letter+digit as identifier, I can tell you this is a ridiculous notion. ==== >> Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. > > How much lexical analysis did you ever do ? Spaces aren't tokens. If you insist on the rigorous definition, spaces might be token, it depends what you put in your lexer. Most of the time a lexer file will contain something like [ t]+ /* skip whitespace */ but there is no obligation to do that. I should better have spoken of number of keystrokes, something calculator users find important. > In any > case, if what you mean is a measure of perceptive/cognitive load of > parsing the two styles of expressions, then put a*b*c*(d+e+f) into the > properly spaced, readable style, that will save the reader's nervous > system from needlessly having to sort out from context, that the *'s and > the +'s of the C expression shouldn't be interpreted as prefix or > postfix operators. > Sorry I don't understand (English is not my native language). If you want to say that spaces should be added in a*b*c*(d+e+f) to give a readable expression, then it's your choice, but I find it perfectly readable. I would add space before and after = for example, but not in that expression. ==== > Actually it is 19 vs 13 if I'm not wrong, you forgot the spaces. > How much lexical analysis did you ever do ? Spaces aren't tokens. > > > If you insist on the rigorous definition, spaces might be token, > it depends what you put in your lexer. Most of the time a lexer > file will contain something like > [ t]+ /* skip whitespace */ > but there is no obligation to do that. Unless the language grammar creates a necessity for it by ascribing a non-standard role to spaces, doing it another way is simply incompetent. > I should better have spoken of number of keystrokes, something > calculator users find important. I thought we were discussing programming languages. > >> In any case, if what you mean is a measure of perceptive/cognitive >> load of parsing the two styles of expressions, then put >> a*b*c*(d+e+f) into the properly spaced, readable style, that will >> save the reader's nervous system from needlessly having to sort out >> from context, that the *'s and the +'s of the C expression shouldn't >> be interpreted as prefix or postfix operators. > > Sorry I don't understand (English is not my native language). Translation : Si ce que vous voulez est une mesure compar.8ee de la charge cognitive/perceptive que comporte l'analyse des deux styles d'expressions, eh bien, .8ecrivez donc d'abord a*b*c*(d+e+f) en un style ad.8equatement a.8er.8e, qui va permettre au syst.8fme nerveux du lecteur l'.8economie d'avoir .88 .8etablir .88 partir du contexte, que les * et les + de l'expression en langage C ne se peuvent interpr.8eter comme des op.8erateurs pr.8efix.8es ou postfix.8es . > If you want to say that spaces should be added in a*b*c*(d+e+f) > to give a readable expression, then it's your choice, but I find > it perfectly readable. I would add space before and after = > for example, but not in that expression. I did not say it was impossible to read, I did say that if you want to count spaces in the lisp expression as a measure of reading complexity, you should take into account that, while C expression syntax allows you to glue the expressions parts together without intervening spaces, this is an operation that fails to alleviate reading complexity : because it makes the burden of disambiguating operator characters all the more acute. ==== > Unless the language grammar creates a necessity for it by ascribing a > non-standard role to spaces, doing it another way is simply incompetent. > I agree. It's just that you take rigorous definitions when I think it is not appropriate, so I decided to be fully rigorous. >> I should better have spoken of number of keystrokes, something >> calculator users find important. > > > I thought we were discussing programming languages. > No we are speaking of representations of mathematical expressions in different programming languages. Sometimes spaces are mandatory, sometimes not. In your lisp expression, spaces are mandatory, therefore counting tokens as in the rigorous definition is not adequate, I find the number of calculator keystrokes in conjunction with being near to the standard mathematical notation to be much more adequate. > Translation : Si ce que vous voulez est une mesure compar.8ee de la charge > cognitive/perceptive que comporte l'analyse des deux styles > d'expressions, eh bien, .8ecrivez donc d'abord a*b*c*(d+e+f) en un style > ad.8equatement a.8er.8e, qui va permettre au syst.8fme nerveux du lecteur > l'.8economie d'avoir .88 .8etablir .88 partir du contexte, que les * et les > + de l'expression en langage C ne se peuvent interpr.8eter comme des > op.8erateurs pr.8efix.8es ou postfix.8es . > Unfortunately the (probably automatic) translation) does not clarify anything. > > I did not say it was impossible to read, I did say that if you want to > count spaces in the lisp expression as a measure of reading complexity, > you should take into account that, while C expression syntax allows you > to glue the expressions parts together without intervening spaces, this > is an operation that fails to alleviate reading complexity : because it > makes the burden of disambiguating operator characters all the more acute. > You are probably not programming frequently in C/C++/any language that use standard math notation for arithmetic. I can insure you that I find a*b*c*(d+e+f) to be much more readable than anything equivalent written with spaces. On the other hand, I would use space before and after =. And of course I will try to use local variables identifiers that are 1 char long to help readability, like mathematicians who use always 1-letter symbols. ==== > > Unfortunately the (probably automatic) translation) does not > clarify anything. ... > > You are probably not programming frequently in C/C++/any language > that use standard math notation for arithmetic. Your presumptions are both totally wrong. Mais comme on dit, il n'y a pire sourd que celui qui ne veut pas entendre, et qui veut tuer son chien l'accuse de la rage. Je vous laisse .88 vos petits jeux d'autiste. Je me contenterai de vous mettre sous le nez que la syntaxe d'expression C est en fait, elle-m.90me, fort loin de la notation mathematique standard. ==== And of course I will try to use > local variables identifiers that are 1 char long to help readability, > like mathematicians who use always 1-letter symbols. This looks like a troll. Certainly this is a foolish argument. Given a common lisp system, you can load in the cgol software. Then you can either run cgol in your lisp, or put #.(cgol) at the top of your file. Then you can do this.. define fib (n) ; if (n=0) then 0 else if (n=1) then 1 else fib(n-1)+fib(n-2) $ fib(4)$ define q(a,b,c); a+b*(c+b)$ etc... You get responses like this..... (cgol(1)> define fib (n) ; if (n=0) then 0 else if (n=1) then 1 else fib(n-1)+fib(n-2) $ lisp> (defun fib (n) (cond ((= n 0) 0) ((= n 1) 1) (t (+ (fib (- n 1)) (fib (- n 2)))))) value> fib cgol(2)> fib(4)$ lisp> (fib 4) value> 3 cgol(3)> define q(a,b,c); a+b*(c+b)$ lisp> (defun q (a b c) (+ a (* b (+ c b)))) value> q cgol(4)> q(1,2,3)$ lisp> (q 1 2 3) value> 11 cgol(5) etc. This is all open source, and you can remove the various messages about lisp. etc. you can return to lisp syntax by typing $$ The original CGOL paper and implementation is quite old, dating to 1973. The cgol software is available in various places, but www.cs.berkeley.edu/~fateman/cgol/cgol.1 is one of them. Also 1.23d0 is like 1.23e0, except it specifies double-precision. ==== > > > > And of course I will try to use > >> local variables identifiers that are 1 char long to help readability, >> like mathematicians who use always 1-letter symbols. > > > This looks like a troll. Certainly this is a foolish argument. Local variable are only relevant to a small area of a program (say 10 to 100 lines), I don't see why identifiers for local variables should be more than 1 char. It's of course not the case for global variables. That's exactly what mathematicians do, they use 1 letter symbols in demonstrations and theorems because the symbols are in some sense local variables in the theorem or demonstration. > Also 1.23d0 is like 1.23e0, except it specifies > double-precision. > > Well after some tries, it seems that d is used for floats (which I never use) and e for doubles. But e is also recognized in e.g. mupad, d is not. Same for calculators. Therefore e is much more standard than d. ==== > That's exactly what mathematicians > do, they use 1 letter symbols in demonstrations and theorems > because the symbols are in some sense local variables in the > theorem or demonstration. No, mathematicians (tend to) use 1 *glyph* symbols, drawn from an arbitrary large alphabet of symbols that borrows from latin, greek, hebrew and adding customizations as necessary to make them sufficiently distinctive. Further, they combine them with a graphical syntax that is nearly 2-dimensional. Using only letters and linear strings, correct equivalents are many-letters identifiers like zeta, hbar or aleph. This goes as well for single-stroke calculator symbols like sin, cos or exp. ==== > >> The precedence of + and * in e.g. a+b*c is taught during highschool. >> It is therefore standard notation and it is more compact than >> (+ a (* b c)) > > > (* a b c (+ d e f)) vs a*b*c*(d+e+f) > > gives 12 tokens vs 13 tokens > Depends on your definition of compact. (* (+ a b c) (+ d e f) (+ g h i) (+ j k l)) gives less tokens than (a+b+c) * (d+e+f) * (g+h+i) * (j+k+l), but the distance your eyes have to travel when you read it is smaller than the first one (you have to keep looking at the * at the beginning of the expression), unless you use more memory (in your mind), which again may take longer to read. This is a trivial example, but if you have multiple functions and multiple operators, and you have to keep counting brackets, it doesn't really matter how many tokens an expression consists of. One more example: many lisp systems allow you to end your expression with ))))))))))) even if there are too many )'s. That's because they acknowledge the problem of balancing parentheses and the time it takes human beings to do it. In C no such thing is needed - you hardly ever have a similar situation, and if anything it indicates bad style rather than a feature of the language. It is possible to argue that you can get used to any language (and that you can use a reasonable editor), but it's still less natural (given the educational system, of course) to read (/ m (sqrt (/ (* v v) (* c c)))) than m / sqrt((v*v)/(c*c)) How many passes are required for your eyes to read the first? The second notation... sqrt 2 is irrational, because if sqrt 2 = / p q, then 2 = / * p p * q q. ==== =, it doesn't > really matter how many tokens an expression consists of. > > One more example: many lisp systems allow you to end your expression > with ))))))))))) even if there are too many )'s. I am not familiar with any such lisp system. I have seen (old) lisp systems which allow you to type ] to close all open parens, or at least up to the last [. This was interlisp, last used in 1985 or so. Almost all editors provide parenthesis matching, flashing the balancing parens as you type. If you are writing programs using any variation of emacs, this is certainly the case. I do not find this requires any intellectual effort, and my freshman students never remark on this. I find the comment that Lisp has too many parentheses to come from people who have only written Lisp with a pencil, and not actually written a program in a lisp environment. That's because they > acknowledge the problem of balancing parentheses and the time it takes > human beings to do it. In C no such thing is needed - you hardly ever > have a similar situation, and if anything it indicates bad style rather > than a feature of the language. > So you never have to think about parenthesis matching? Maybe you should look at my earlier post. Can you write f(a+f(b+f(c+f(d+e)....) in C? Maybe it is your poor programming style? By composing functions, a very powerful technique, you can write very concise and well-structured computations. They tend to look like nested functions, and they tend to end with lots of ))))) ! > It is possible to argue that you can get used to any language (and that > you can use a reasonable editor), but it's still less natural (given the > educational system, of course) to read > > (/ m (sqrt (/ (* v v) (* c c)))) > > than > > m / sqrt((v*v)/(c*c)) It is also natural to do what a physics textbook of mine did, which was to say 1/2pi f(x) and mean 1/(2* pi) * f(x) instead of (1/2) * pi * f(x) which is what a programmer might think. So what is natural is sometimes wrong. Also the precedence of * and + is not the only issue. you need to know the precedence and binding of ^. e.g. a^b^c. And you need to know the precedence of == & | && || . Many programmers do not know the precedence of operators. I think that in C there are 13 levels, and * occurs in 3 different ones, with different meanings. Confusion between = and == is a common source of serious errors. Do you, offhand, know if you need parentheses in a==b&c++ or p+q p+++q p+++++q How many passes do you need to understand these, if in fact they make sense? > > How many passes are required for your eyes to read the first? The second > notation... > > sqrt 2 is irrational, because if sqrt 2 = / p q, then 2 = / * p p * q q. This is not actually a difficult task. 2 = (/ (* p p) (* q q)) is, I think, pretty easy to read. For large expressions, such a layout is a major improvement. It actually reflects the algebraic tree of the operators, turned sideways. For small expressions you might want to have an infix reader installed in your lisp system, mentioned earlier, so you could write (setf z #.[p^2/q^2]) or you could write a whole file of lisp beginning #.[ .... and ending ] so that your whole file is in infix. Actually, the parser for Macsyma, written in Lisp, can be embedded this way, so you can insert arbitrary Macsyma expressions in Lisp source code. The Reduce system has had such a system (called, I think, Algebraic Mode?) of infix, for maybe 30 years. The CGOL system is an Algol-like version of Lisp that has been around for 30 years or so too. The syntax is not an issue for the vast majority of people who have tried lisp. It is that way because it is good. It is not that way as a punishment, or because it is a negative consequence of the design. It is a benefit. > ==== > (* (+ a b c) (+ d e f) (+ g h i) (+ j k l)) gives less tokens than > > (a+b+c) * (d+e+f) * (g+h+i) * (j+k+l), but the distance your eyes have > to travel when you read it is smaller than the first one (you have to > keep looking at the * at the beginning of the expression), unless you > use more memory (in your mind), which again may take longer to read. I don't buy this argument *at all*, since associativity and precedence rules of infix notation make the parse tree unstable with respect to substitution of operators. But frankly, I find the difference minute in any case. Don't read me wrong, I do like infix notation, but the experience of having to collaborate to a lisping team forced me to quickly acknowledge prefix-style as very competitive in practical readability. For instance, I see > (/ m (sqrt (/ (* v v) (* c c)))) and > m / sqrt((v*v)/(c*c)) as quite equivalent, with a slight advantage to the first form because of the double (( of the infix style. Imho the parsing cost of multiple opening parentheses is much higher than for closing parentheses : I invite you to check that to parse the first expression, it is sufficient to assume that the closing parens balance and not necessary to detail what each one balances, while in the case of the second form you do need to match the parens individually. ==== > I'm a mathematician, and again I can insure you I never > saw this notation before. Which means for me a couple > of (integers or polynomials). Maybe it's a local US notation. Sorry, parisse, I'm a (austrian-french) mathematician too, and I also know *only* (b,c) for gcd. Of course, I use it also for pairs and there are probably other things I use it for too. I never saw the symbol ^ used for gcd though. You are not trolling, are you? Martin ==== > > >>I'm a mathematician, and again I can insure you I never >>saw this notation before. Which means for me a couple >>of (integers or polynomials). Maybe it's a local US notation. > > > Sorry, parisse, I'm a (austrian-french) mathematician too, and I also know > *only* (b,c) for gcd. Of course, I use it also for pairs and there are probably > other things I use it for too. I never saw the symbol ^ used for gcd though. > It's not the exponent symbol but the and symbol (i.e. move a little bit ^ down). But as I said in my first or 2nd post in this thread, there is no standard mathematical notation for gcd, hence gcd(a,b) is the only reasonable notation. > You are not trolling, are you? Of course not. If you think so, you should ask yourself the same question seeing some arguments in this thread... ==== I would like to make a secondary axis in MathCAD 2000 Professional. i.e. I want to plot two functions on the same graph, but I want different scales for the two functions. Excel can do this for the y-axis. I can't figure out whether MathCAD can do it at all. Ideally I'd likw to be able to do this for both axes.