Menu

#3999 asksign(cos^2 - 1)

None
open
nobody
asksign (22)
5
2022-07-02
2022-06-27
No

When asking to

integrate(1/(1 - cos(phi)^2*sin(x)^2), x, 0, %pi/2);

the user is asked "Is 1 zero or nonzero?", which is somewhat funny, somewhat strange, and gives no clue about whats going on. Adding "trace(?asksign1);" reveals that integrate wants to know the sign of "4cos (phi) ^2 - 4" which would have been precious to the user, and would have suggested a "assume(4cos (phi)^2 - 4 < 0)".

But what is more disturbing is, how did this question come up at all when looking
at "cos^2 - 1". How did it internally arrive at a point from where the sign of "1" would become interesting.

Thus more interesting is this trace

trace(?asksign1);
trace(?sign\-prep);
trace(?ensure\-sign); 
trace(?sign1); 
asksign(cos(phi)^2 - 1);

from a glimpse at the trace printout, and another glimpse at "compar.lisp"
I'd guess there is too much passing values by "special" variables from
function to function, and something might have been overwritten that way.

I think it is worth having a thorough look at this testcase.

Regards,
Robert

Discussion

  • Barton Willis

    Barton Willis - 2022-06-27

    The "Is 1 zero or nonzero?" bug has been with us for a long time--it pops up occasionally. I'd guess the source code has workarounds for this bug, but it's never been fixed.

    Any help or insight to fixing this bug would be terrific.

     
  • Robert Larice

    Robert Larice - 2022-06-27

    this shorter testcase:

    asksign(cos(phi) - 1);
    

    without the square is easier to trace and is sufficient for debugging.

    in compar.lisp there is (defun asksign1...) which invokes (sign1 ...) on the given expression.
    Here the result will be $NZ which I guess shall mean negative or zero.
    so far so good.
    then a (cond ) follows and the (null odds) will be choosen.
    here the defun argument $askexp will be setq'ed to something new, namly (lmul evens).
    it happens evens is nil, and lmul returns 1 for this.
    few lines deeper the interactive function ensure-sign will be invoked with this new expression being "1" as the user shall now decide either pos neg or zero, the $nz was not decisive enough.
    and thus we are asked whether "1" is zero.

    problem is, I don't know what evens and odds is meant to be. I can only guess the case
    of both being nil was not anticipated.

    By the way, while stepping through the code somewhere around sign1 I saw integer numbers
    1 and 0 being converted to floats. isnt that ugly for a symbolic engine ?. futhermore there is
    somewhere a < 1e-6 in compar.lisp which seems even uglier.

     
  • Stavros Macrakis

    Evens and odds are subexpressions that are even or odd functions. They are dynamic variables that are set in various places in compar.lisp. Old-fashioned coding style, but....

     
    • Robert Larice

      Robert Larice - 2022-06-28

      How exactly do you think the whole expression is related to the subexpression ?
      for example

      -5 * x^4 * y^5 * (x+1)^6 * (y+2)^7
      

      do you think this gives rise to
      special variable minus being t
      odds being a list of y and (y+2)
      evens being a list of x and (x+1)
      is it meant to work that way ?

      then I'd expect

      1 - cos(x)
      

      to be split into
      minus nil
      odds list with one element (1-cos(x))
      evens nil

      Regards,
      Robert

       
  • Barton Willis

    Barton Willis - 2022-06-27

    Here the result will be $NZ which I guess shall mean negative or zero.

    Yes, $NZ is negative or zero, $PZ is positive or zero, and ... The user documentation for sign (enter ? sign) lists all possibilities for the output of sign.

    About evens and odds. It seems that since there are no even expressions and no odd expressions, asksign1 should be free to return $NZ?

    By the way, while stepping through the code somewhere around sign1 I saw integer numbers
    1 and 0 being converted to floats. isnt that ugly for a symbolic engine ?.

    Yes, it is ugly. What happens if you disable it? Does the testsuite run to completion?

     
    • Robert Larice

      Robert Larice - 2022-06-27

      "Barton Willis" willisbl@users.sourceforge.net writes:

      Here the result will be $NZ which I guess shall mean negative or zero.

      Yes, $NZ is negative or zero, $PZ is positive or zero, and ... The user documentation for sign (enter ? sign) lists all possibilities for the output of sign.

      About evens and odds. It seems that since there are no even expressions and no odd expressions, asksign1 should be free to return $NZ?

      I don't think so. There is some place in signdiff-special where it
      actually looks at cos(x)+constant, and makes up its mind.
      Here cos(x)-1 will be correctly decided to be $nz, negative or zero.
      But asksign1 can only return positive zero or negative, thus $nz is not
      precise enough. Thus it decides to interact with the user and ask him with
      the function ensure-sign. and before it invokes this it reassembles a
      expression $askexp which originally was cos(phi)-1 which will then be
      presented to the user instead of the original expression. It reassembles this
      from the odds and evens list only, and because both of them are empty
      and because the reassembly is done by (lmul...) presumable "multiply all
      things in a list", empty list counts as "1". Maybe one simply shouldnt
      setq to $askexp when both lists are empty. But this is difficult to
      decide for me with all those special vars around and with my exremly
      limited understanding of whats going on here.

      here is an example:
      asksign((cos(phi)-1) * phi^2 * rho^3)
      will produce an odds list with the single element rho
      and an evens list with the single element phi
      the reassembly then produces
      odds * evens^2 --> rho * phi^2

      less exponents but still sufficient to find the sign.

      By the way, while stepping through the code somewhere around sign1 I saw integer numbers
      1 and 0 being converted to floats. isnt that ugly for a symbolic engine ?.

      Yes, it is ugly. What happens if you disable it? Does the testsuite run to completion?

      It is by far not that easy that I could try it. I just wondered why such
      things pop up during my tracing action. in cos(phi) - 1 there is no
      float whatsoever to be seen, and nontheless suddenly they pop up in the
      trace. certainly it has nothing to do with the "1" question thing.

       
  • Robert Larice

    Robert Larice - 2022-06-27

    things get worse.

    If I asksign((cos(x) - 1) * phi^3)
    it will ask me "Is phi positive, negative or zero?"
    it asks me only about phi.
    If I answer positive then its response is "pos" which is clearly completely bogus.
    Thus is not only forgets to reassemble the cos(x)-1 into the $askexp variable when
    preparing for the interactive question in ensure-sign. It completely forgets that this part is $nz.

     
  • Robert Dodier

    Robert Dodier - 2022-06-28

    Here is a possible patch (not well-tested):

    diff --git a/src/compar.lisp b/src/compar.lisp
    index 5afbe2a4f..b44fc70c4 100644
    --- a/src/compar.lisp
    +++ b/src/compar.lisp
    @@ -914,6 +914,7 @@ relational knowledge is contained in the default context GLOBAL.")
         (t
          (let ((domain sign) (squared nil))
            (cond
    
    +         ((and (null evens) (null odds))) ;; don't update $ASKEXP, DOMAIN, or SQUARED
              ((null odds)
               (setq $askexp (lmul evens)
                     domain '$znz
    

    That's enough to avoid "Is 1 negative or zero?" mentioned in this report. I haven't tried existing bug reports about "Is 1 something or the other?".

    It doesn't change the results for the "forgotten term" bugs also mentioned in this bug report; those probably need a separate report.

     
    • Robert Larice

      Robert Larice - 2022-06-28

      I'd propose something too, almost untested.
      Inspired by something similiar found in signsum but absent in signdiff.

      diff --git a/src/compar.lisp b/src/compar.lisp
      index 5afbe2a4f..88cf483de 100644
      --- a/src/compar.lisp
      +++ b/src/compar.lisp
      @@ -1453,6 +1453,7 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
                       ((signdiff-special lhs rhs))))))
           (if swapped
             (setq sign (flip sign)))
      
      +    (setq minus nil odds (list x) evens nil)
           retval))
      
       (defun signdiff-special (xlhs xrhs)
      

      I will need some time to check and think about it.

       
      • Robert Larice

        Robert Larice - 2022-06-29

        make check works.
        asksign(cos(x)-1) and some others work.
        but asksign(1-cos(x)) somewhere looses a sign.

         
        • Robert Larice

          Robert Larice - 2022-07-02

          I attach a revised patch which cares about the sign problem as well.
          make check works,
          batch("maxima-code/tests/test_asksign1.mac", test); works

          first remove an ancient leftover artifact

          --- a/src/compar.lisp
          +++ b/src/compar.lisp
          @@ -919,7 +919,6 @@ relational knowledge is contained in the default context GLOBAL.")
                           domain '$znz
                           squared t))
                    (t
          
          -          (if minus (setq sign (flip sign)))
                     (setq $askexp
                           (lmul (nconc odds (mapcar #'(lambda (l) (power l 2)) evens))))))
                  (setq sign (cdr (assol $askexp *local-signs*)))
          

          then try to fix the issues:

          --- a/src/compar.lisp
          +++ b/src/compar.lisp
          @@ -919,6 +919,8 @@ relational knowledge is contained in the default context GLOBAL.")
                           domain '$znz
                           squared t))
                    (t
          
          +          (when minus
          +            (setq domain (flip domain)))
                     (setq $askexp
                           (lmul (nconc odds (mapcar #'(lambda (l) (power l 2)) evens))))))
                  (setq sign (cdr (assol $askexp *local-signs*)))
          @@ -1459,8 +1461,9 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
                            t)
                           ((and (not (atom lhs)) (eq (caar lhs) 'mabs)
                                 (alike1 (cadr lhs) rhs))
          -                 (setq sign '$pz minus nil odds nil evens nil) t)
          -                ((signdiff-special lhs rhs))))))
          +                 (setq sign '$pz minus nil odds (list x) evens nil) t)
          +                ((let ((rv (signdiff-special lhs rhs)))
          +                   (setq odds (list x) evens nil) rv))))))
               (if swapped
                 (setq sign (flip sign)))
               retval))
          

          which fixes tree issues:
          1) 1-cos did pose the "1" question, because odds was not set
          2) abs(x)-x did pose the "1" question, because odds was not set
          3) when the "1" question was fixed, 1-cos posed an incorrect question
          because the domain was not flipped when minus was set

           
          • Robert Larice

            Robert Larice - 2022-07-02

            here is a bit of a test facility, for debugging purpose only.
            It is ment to check not only askasign1 return values, but as well the
            asked domain questions ant their expressions.
            it can be run like this:
            batch("maxima-code/tests/test_asksign1.mac", test);
            some tests are stolen from rtest_ask, others popped up during search for the bug.
            test_asksign1.mac is attached.

            --- a/src/compar.lisp
            +++ b/src/compar.lisp
            @@ -952,6 +952,8 @@ sign of the square, so any negative results are converted to positive."
                     (setq sign
                           (if minus (flip found-sign) found-sign))))))
            
            +(defmvar $expect nil)
            +
             (defun ensure-sign (expr &optional domain squared)
               "Try to determine the sign of EXPR. If DOMAIN is not one of the special values
             described below, we try to tell whether EXPR is positive, negative or zero. It
            @@ -967,7 +969,10 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
               (loop
                  (let ((new-sign (match-sign sign domain expr squared)))
                    (when new-sign (return new-sign)))
            
            -     (setf sign (retrieve
            +     (setf sign
            +           (if $expect
            +               (retrieve-from-$expect expr domain)
            +               (retrieve
                              (list '(mtext)
                                    "Is " expr
                                    (or (second
            @@ -977,7 +982,20 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
                                                  ($nz  " negative or zero?")
                                                  ($pn  " positive or negative?"))))
                                        " positive, negative or zero?"))
            -                 nil))))
            +                 nil)))))
            +
            +
            +;;; fixme use $pop to pop expectations ?
            +(defun retrieve-from-$expect (expr domain)
            +  (let ((qexpr (cadr $expect))
            +        (quest (caddr $expect))
            +        (answer (cadddr $expect)))
            +    (if (and (alike1 expr qexpr)
            +             (equal domain quest))
            +        (setf $expect nil)
            +        (merror (intl:gettext "asksign, expect doestn match ~:M ~:M (~:M)")
            +                expr domain qexpr))
            +    answer))
            
             ;; During one evaluation phase asksign writes answers from the user into the
             ;; global context '$initial. These facts are removed by clearsign after
            
             
  • Robert Dodier

    Robert Dodier - 2022-06-28
    • labels: --> asksign
     

Log in to post a comment.

MongoDB Logo MongoDB