From: Rupert Swarbrick <rswarbrick@us...>  20140728 21:16:45

This is an automated email from the git hooks/postreceive script. It was generated because a ref change was pushed to the repository containing the project "Maxima CAS". The branch, master has been updated via 71578fbaaeaebeb632f7446ece47c79235ebc767 (commit) via f9db5cbac9b7db100b6db706ff688272307250a8 (commit) from a11f1a4829c8794bdf9898e51dc23cc68107aa84 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.  Log  commit 71578fbaaeaebeb632f7446ece47c79235ebc767 Author: Rupert Swarbrick <rswarbrick@...> Date: Mon Jul 28 22:13:57 2014 +0100 Avoid splitting out negative terms in SP1LOG This should fix bug #2775 diff git a/src/trgred.lisp b/src/trgred.lisp index 889eb3e..47b7257 100644  a/src/trgred.lisp +++ b/src/trgred.lisp @@ 446,6 +446,25 @@ (m^ '$%e exp)) ((m* (m^ '$%e fr) (m^ '$%e exp)))))) +;; Split TERMS into (VALUES NONNEG OTHER) where NONNEG and OTHER are a +;; partition of the elements of TERMS. Expressions that are known not to be +;; negative are placed in NONNEG and all others end up in OTHER. +;; +;; This function is used to safely split products when expanding logarithms to +;; avoid accidentally ending up with something like +;; +;; log(1  x) => log(1) + log(x1). +;; +;; Note that we don't check a term is strictly positive: if it was actually +;; zero, the logarithm was bogus in the first place. +(defun nonnegativesplit (terms) + (let ((nonneg) (other)) + (dolist (term terms) + (if (memq ($sign term) '($pos $pz $zero)) + (push term nonneg) + (push term other))) + (values nonneg other))) + ;; Try to expand a logarithm for use in a power series in VAR by splitting up ;; products. (defun sp1log (e &optional norecurse) @@ 470,8 +489,18 @@ ;; A product is much more promising. Do the transformation log(ab) => ;; log(a)+log(b) and pass it to SP1 for further simplification. + ;; + ;; We need to be a little careful here because eg. factor(1x) gives + ;; (x1). We don't want to end up with a log(1) term! So check the sign of + ;; terms and only pull out the terms we know to be nonnegative. If the + ;; argument was a negative real in the first place then we'd already got + ;; rubbish, but otherwise we won't pull out anything we don't want. ((eq (caar e) 'mtimes)  (sp1 (m+l (mapcar #'sp1log (cdr e))))) + (multiplevaluebind (nonneg other) (nonnegativesplit (cdr e)) + (cond + ((null nonneg) (sp1log2 e)) + (t + (sp1 (m+l (mapcar #'sp1log (cons other nonneg)))))))) ;; Similarly, transform log(a^b) => b log(a) and pass back to SP1. ((eq (caar e) 'mexpt) diff git a/tests/rtest16.mac b/tests/rtest16.mac index 6f3be7b..224c4ac 100644  a/tests/rtest16.mac +++ b/tests/rtest16.mac @@ 2020,3 +2020,10 @@ powerseries(x^x,x,0); sumcontract(intosum(powerseries(1+ (1x)^(a),x,0)  powerseries((1x)^(a),x,0))); 1$ + +/* + #2775: Don't expand a powerseries with log(ab)=log(a)+log(b) if a + is negative +*/ +(gensumnum : 0, powerseries (log(2x), x, 0)); +sum(2^(i11)*x^(i1+1)/(i1+1), i1, 0, inf)$ commit f9db5cbac9b7db100b6db706ff688272307250a8 Author: Rupert Swarbrick <rswarbrick@...> Date: Mon Jul 28 21:52:32 2014 +0100 Add some comments to SP1LOG explaining what it's doing Also, get rid of the *SP1LOGF* special variable, which is only used to avoid recursion in this function. Replace it with an optional norecurse argument, which is much easier to understand. diff git a/src/trgred.lisp b/src/trgred.lisp index 69708ca..889eb3e 100644  a/src/trgred.lisp +++ b/src/trgred.lisp @@ 45,7 +45,6 @@ (defvar *laws*) (defvar *trigbuckets*) (defvar *hyperbuckets*) (defvar *sp1logf* nil) ;;The Trigreduce file contains a group of routines which can be used to ;;make trigonometric simplifications of expressions. The bulk of the @@ 447,24 +446,40 @@ (m^ '$%e exp)) ((m* (m^ '$%e fr) (m^ '$%e exp)))))) (defun sp1log (e)  (cond ((or *trigred (atom e) (free e var))  (list '(%log) e))  ((eq (caar e) 'mplus)  (let* ((exp (m1 e))  (*a nil)  (*n nil))  (declare (special *n *a))  (cond ((smono exp var)  (list '(%log) e))  (*sp1logf* (sp1log2 e))  ((let* ((*sp1logf* t))  (sp1log ($factor e)))))))  ((eq (caar e) 'mtimes)  (sp1 (m+l (mapcar #'sp1log (cdr e)))))  ((eq (caar e) 'mexpt)  (sp1 (m* (caddr e) (list '(%log) (cadr e)))))  ((sp1log2 e)))) +;; Try to expand a logarithm for use in a power series in VAR by splitting up +;; products. +(defun sp1log (e &optional norecurse) + (cond + ;; If E is free of VAR, is an atom, or we're supposed to be reducing rather + ;; than expanding, then just return E. + ((or *trigred (atom e) (free e var)) + (list '(%log) e)) + + ;; The logarithm of a sum doesn't simplify very nicely, but call $factor to + ;; see if we can pull out one or more terms and then recurse (setting + ;; NORECURSE to make sure we don't end up in a loop) + ((eq (caar e) 'mplus) + (let* ((exp (m1 e)) *a *n) + (declare (special *n *a)) + (cond + ((smono exp var) + (list '(%log) e)) + ((not norecurse) + (sp1log ($factor e) t)) + (t (sp1log2 e))))) + + ;; A product is much more promising. Do the transformation log(ab) => + ;; log(a)+log(b) and pass it to SP1 for further simplification. + ((eq (caar e) 'mtimes) + (sp1 (m+l (mapcar #'sp1log (cdr e))))) + + ;; Similarly, transform log(a^b) => b log(a) and pass back to SP1. + ((eq (caar e) 'mexpt) + (sp1 (m* (caddr e) (list '(%log) (cadr e))))) + + ;; If we can't find any other expansions, pass the result to SP1LOG2, which + ;; tries again after expressing E as integrate(diff(e)/e). + ((sp1log2 e)))) (defun sp1log2 (e) (and $verbose  Summary of changes: src/trgred.lisp  82 ++++++++++++++++++++++++++++++++++++++++ tests/rtest16.mac  7 ++++ 2 files changed, 70 insertions(+), 19 deletions() hooks/postreceive  Maxima CAS 