Menu

#4923 sign(COMPLEX) => pnz

None
open
nobody
5
5 days ago
5 days ago
No
sign(%i);
   => sign: argument cannot be imaginary; found %i  <<< CORRECT

declare(z,complex)$
sign(z) => pnz <<< Should give error

Discussion

  • Stavros Macrakis

    • labels: --> sign, complex
     
  • David Scherfgen

    David Scherfgen - 5 days ago

    The difference is that %i is provably non-real, while z can be non-real.

    Erroring on sign(z) would treat "nothing known about realness" the same as "provably non-real". It also has a cost outside of sign itself. is() routes through sign and converts this error into false (meaning "provably no") - the same path that makes is(%i > 0) false today.

    So, if sign(z) raised an error, then is(z > 0) and is(z < 0) would both change from today's answer unknown to false ("provably no"). That would imply that a variable declared complex always has a non-zero imaginary part or is zero, which would in turn collide with csign's answer on e.g. log(x), where complex means "possibly non-zero imaginary part".

     
    • Stavros Macrakis

      Yes, z might be real, but I disagree that sign should assume that it is real and thus return pnz.

      The root problem is that sign has no way to return unknown other than signaling an error. If is depends on the current behavior, that is a bug in is.

      cf. my comments in #4922.

       
      • David Scherfgen

        David Scherfgen - 5 days ago

        I agree the root problem is that sign has no way to say "not known to be real". But the error can't fill that role, because is has to treat two cases differently: %i and a declared-imaginary j are definitely not real, so is(%i > 0) => false is correct. z is only possibly not real, so is(z > 0) has to stay unknown. If the error becomes false, z is handled wrong; if it becomes unknown, is(%i > 0) breaks.

        So why not give sign the missing answers instead: let it return imaginary or complex (as csign already does) when the declarations leave no better option. Then sign(z) => complex, sign(j) => imaginary, sign(j^2) => nz, and is maps imaginary to false and complex to unknown. asksign would still reject anything not known to be real.

        sign and csign would still differ in the same way as before: csign(sqrt(x)) => complex for undeclared x, while sign keeps treating undeclared variables and operations on them as real (sign(sqrt(x)) => pz, unless a fact says that x < 0). Only declarations would make sign return a complex answer.

        One concern: sign returning values outside the documented seven could break internal callers and external code that do a case analysis on the result. My hope would be that most callers just test for specific values like pos and fall through otherwise, so complex would act like pnz does today rather than cause errors - but that remains to be seen.

         
        • Stavros Macrakis

          Re is(%i>0) is not false, but meaningless since %$i is not part of the ordered field R. It should return unknown, just as other meaningless statements do, e.g. is([1]>0) and is({}<[]) return unknown.

           
        • Stavros Macrakis

          Re "So why not give sign the missing answers instead: let it return imaginary or complex (as csign already does) when the declarations leave no better option. Then sign(z) => complex, sign(j) => imaginary, sign(j^2) => nz, and is maps imaginary to false and complex to unknown. asksign would still reject anything not known to be real."

          The raison d'être of csign is precisely that the return values of sign are a closed set. We can't "hope" that our users' code doesn't depend on this.

           
          • David Scherfgen

            David Scherfgen - 5 days ago

            The error can of course break existing code too, though at least in a more visible way.

            How about this: Internally, let the imaginary/complex values flow through the machinery (as in csign), and fire the error only if the final result is still imaginary or complex. That would allow sign(j^2) => nz instead of an error on a provably real quantity.

            is catches the error and would map it to unknown instead of false as you suggested, giving is(z > 0) => unknown, is(j > 0) => unknown and is(j^2 <= 0) => true. sign(sqrt(x)) stays pz for undeclared x of unknown sign, which is where sign would still differ from csign.

             

Log in to post a comment.

MongoDB Logo MongoDB