chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.76k stars 414 forks source link

Surprising behavior of Math.sqrt results in loss of precision #24496

Closed twesterhout closed 3 months ago

twesterhout commented 4 months ago

Summary of Problem

It seems that invoking sqrt with integral arguments doesn't consistently convert them to real(64). For instance,

writeln(try! "%.20r".format(sqrt(2:uint(16))));
writeln(try! "%.20r".format(sqrt(2:uint(16):real)));

results in

1.4142135381698608398
1.4142135623730951455

Even though one can say that real(32) is sufficient to store a uint(16) value, and that's why sqrt is computed for real(32), I'd like to argue that this behavior can introduce very difficult to track bugs. In C, integral types are promoted to double before passing them to math functions (https://en.cppreference.com/w/c/numeric/math/sqrt): Godbolt test)%3B%0A++++fprintf(stderr,+%22%25.20lf%5Cn%22,+(double)sqrt(2.0))%3B%0A++++fprintf(stderr,+%22%25.20lf%5Cn%22,+(double)sqrtf(2.0f))%3B%0A++++return+0%3B%0A%7D'),l:'5',n:'0',o:'C+source+%231',t:'0')),k:48.87005649717514,l:'4',m:100,n:'0',o:'',s:0,t:'0'),(g:!((h:executor,i:(argsPanelShown:'1',compilationPanelShown:'0',compiler:cg132,compilerName:'',compilerOutShown:'0',execArgs:'',execStdin:'',fontScale:14,fontUsePx:'0',j:1,lang:___c,libs:!(),options:'',overrides:!(),runtimeTools:!(),source:1,stdinPanelShown:'1',tree:0,wrap:'1'),l:'5',n:'0',o:'Executor+x86-64+gcc+13.2+(C,+Editor+%231)',t:'0')),k:51.12994350282486,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4). Moreover, C compilers have warnings such as -Wdouble-promotion that allow detecting cases when, e.g., a float is multiplied by a double. Chapel doesn't seem to warn about such cases and happily computes sqrt for real(32) and then promotes the result to real(64) when multiplied by real(64), and such errors may be very difficult to track in a bigger program.

Would it be possible for Chapel to follow C & C++ here? Or could calls like sqrt(x:uint(16)) trigger a error or at least a warning?

Thanks!

bradcray commented 4 months ago

Hi Tom — Thanks for filing this issue. I know we did some work here to try and align more with C/C++ a few years back, but I can't recall whether the behavior you're seeing indicates a case we missed or an intention that I'm forgetting. Let me tag @mppf on this, who led that effort in hopes that he remembers better than I do.

damianmoz commented 4 months ago

I fully support the underlying rule that a real(w) expression will not be influenced by any integers therein, i.e. an expression with real(32) and integers of any precision stays as real(32). Otherwise,. lots of things break, badly, many of which can also take a long time to track down when a language does not do that.

However, Tom's case in point is what happens when the expression is purely integral.

My paraphrasing of the default rule (which I fully support) is that an integer which is (or can be) represented in an int(w) maps to real(w) as Chapel does currently. However, I fully support Tom's suggestion that it would be extremely useful if the compiler issue a warning of possible loss of precision (unless that warning is suppressed). I think I have suggested this in the past but put a non-urgent tag on it. I did have a look at what be required with a view to changing it myself until I realized that it was outside my skill set.

One could also have an option that by default promotes any integral expression to real(64). While it would be an option I would never use, it would help in your case Tom. That said, I would consider such use extremely dangerous.

An even more useful option would be one that raises an error when any purely integral expression is passed to a function whose argument is real(w). I would find that option extremely useful and it would catch lots of errors.

Our programming practice is that we mandate that any integral expression be explicitly cast to the type it needs to be when being assigned to a variable of type real(w) or being passed to an argument of type real(w). So the error which Tom mentions never arises in our day-to-day work unless we have been less than careful. But currently, we have to identify such errors manually by code-reviews.

bradcray commented 4 months ago

My paraphrasing of the default rule (which I fully support) is that an integer which is (or can be) represented in an int(w) maps to real(w) as Chapel does currently.

Oh yeah, thanks for the comment Damian. I think you're correct that this was a guiding principle in the recent work I was referring to—that if I'm computing with 32-bit values (because I'm on a 32-bit platform, say), we should preserve that width rather than inflating things to a wider precision for the user and requiring them to downcast to stay at the specific size. Of course, we don't have a real(8) or real(16) currently, so if int(32) goes to real(32), it makes sense to me that int(16) also goes to real(32) rather than real(64). @twesterhout, do you buy that argument?

I'd be on-board with a warning to warn users of cases like this, and also remain on-board with Damian's broader desire for a way to opt out of implicit conversions—though I usually propose doing that with a pseudo-module like use NoImplicitConversions; rather than a compiler flag so that the assumption is visible in the text of the source code rather than relying on a reader to know what the command-line is expected to be (and the module also permits the behavior to be scoped rather than being broadly applied to an entire program or file).

damianmoz commented 4 months ago

When Chapel starts to get more heavily used for AI/ML, and it seems ideally placed/suited for it, you might want to preserve the int(16)/real(16) conversions in many situations where the underlying hardware supports it. But there are other situations where you want to upscale. I am still trying to wrap my brain around IEEE P3109's 8-bit mini-float document so I cannot begin to comment intelligently on the real(8) stuff.

Yes, I would like to opt-out of implicitly conversions during development and debugging. But it is not essential. I am happy to have implicit conversions in my code as they often greatly enhance readability, especially where source code is the ultimate documentation for an algorithm. In that context, I would like to have the compiler tell me where it sees those conversions because they can be a source of pain and frustration (when I sadly get them wrong).

I like the idea of a pseudo module but I would like a way to disable it on the command line without having to resort to commenting it out in the source code which might default to read-only in a master copy, especially during testing.

Please notice the edit in the first paragraph.

mppf commented 4 months ago

Yeah, I think the comments so far match my understanding. I agree that a warning in this case would be welcome.

Oddly enough, thinking of adding real(16): I think that introduces a language stability problem for cases like this, because say sin(myInt16) would result in a real(16) rather than the real(32) we get today. As a result, we might want to make these cases also generate a --warn-unstable warning. (Or we could see if it occurs rarely enough that an error is suitable).

twesterhout commented 4 months ago

Hello Brad, Damian, and Michael. Sorry for the delay -- busy day. The arguments that Damian is making totally make sense to me. I do think that there are two slightly separate issues that we're discussing. The first issue is whether and how integral types should be promoted to real or complex types if they appear in an expression containing real/complex arguments. The second is whether and how integral types should be promoted to real or complex types if they are passed to mathematical functions whose natural domain is ℝ or ℂ.

I don't have much to comment on the first issue -- I think it's been covered by Damian and Michael -- except to say that there, we're not talking about a loss of precision (e.g., uint(16) fits nicely into a real(32), so it's safe; uint(16) to real(16) and uint(32) to real(32) would be a different story though...).

In the second issue though (i.e., sqrt(x:uint(16))), uint(16) is the only type that appears in the expression, so I think the choice to convert it to real(32) instead of real(64) is less clear. For instance, C & Julia convert to real(64), but NumPy converts to real(32). There's also the standard "use real(64) unless you know what you're doing" advice (because lower precision floats are much less forgiving and require more thought on the programmer's side), so it would seem that converting to real(64) is more beginner friendly. Of course, a drastically different approach is to forbid any implicit integral to real conversions like Haskell does (which actually matches the hardware -- at least that's what I know about x86-64), but even though I personally quite like it, it is probably not the best approach for Chapel :smiley:

In any case, a compiler warning would be very highly appreciated. And potentially a warning in the documentation? (E.g., in the form of a "notable differences from X" page or at the beginning of the Math module)

damianmoz commented 4 months ago

I could comment here on your paragraph starting with In the second issue though. However, the full answer is a bit out of scope and is related to decisions made before the introduction of the IEEE floating point standard. I can reply by email on this if you want the gory/sad details.

You did mention that

There's also the standard "use real(64) unless you know what you're doing" advice (because lower precision floats are much less forgiving and require more thought on the programmer's side), so it would seem that converting to real(64) is more beginner friendly.

Chapel has you covered there if you stick to using an int type, and a real type, because it uses 64 bits for such types. So it is already beginner friendly. And because 64-bit integral types convert to 64-bit floating point types, Chapel is also staying consistent with rules for lesser precision integral types.

From the sounds of it, the compiler warning you are requesting looks like it is coming sooner rather than later. I can/will draft up some words (in the next few weeks) that might be suitable for inclusion at the start of the Math module. After Easter. They might/will need some iteration to get them sounding like they fit (and are not too waffly).

You note that a drastically different approach is to forbid any implicit integral to real conversions like Haskell does. As Brad noted, I too have suggested such a feature although unlike Haskell, I think it should be optional. I believe there is a consensus there on having this in the future. So this should be able to catch such problems. What its priority is, I will leave to others far more au-fait with the human resources available.

Just for the record, the approach of converting things to double precision by default can also cause just as many, if not more and worse errors in C/C++ (and Chapel up until reasonably recently, well, at least pre-COVID). Of more concern is that this approach often hides the real problem and just postpones (and makes it harder) finding the offending code. I am dealing with just such a problem right now in a Smoothed Particle Hydrodynamics application - not fun.

bradcray commented 4 months ago

Skipping back to @twesterhout's last comment:

For instance, C & Julia convert to real(64)

Tom, how are you evaluating C's conversions here? For example, a case like the one in the OP doesn't really have an equivalent in C since it doesn't support overloading and has distinct sqrt() vs. sqrtf() routines for double vs. float. So if the test was "What does sqrt((int16_t)2) do in C?", it's not surprising it converts to double since that's the only routine available and it's a legal conversion. (If it's not obvious, note that Chapel supports two overloads of sqrt(), one that takes real and one that takes double).

Setting up a similar example with overloading, in C++, I wasn't sure what I'd get, but it looks like the answer is an ambiguity error—surprisingly to me, even for integers of larger fixed widths like int32_t or int64_t.

We could consider doing the same thing in Chapel, though that feels like a big change to make now, and I feel somewhat reassured if our behavior does match NumPy.

I'll also mention that, at least once recently, I've asked whether we should consider having an IntMath module that would define things like sqrt() on ints to return ints rather than promoting to floating point. On one hand, I think this would be fairly different than what other languages do; on the other hand, it's pretty similar to how operators like / work—preserving type, even if it results in a less precise answer.

Should we fork off the "Have Chapel warn about implicit conversions from int(w) to real(w2) where w < w2" into its own issue, or just have this issue's action item be to do just that?

damianmoz commented 4 months ago

Chapel's behaviour matches Fortran (as well as numpy) and also, as you say.

sqrtf((int16_t) 2)

Chapel's behaviour for such scenarios is more rigorous than C. It is very well defined.

I currently define (and I am just racing out the door so I might have a typo)

inline proc sqrt(param x : int(?w), type T = real(64)) param
{
    ....
}

which allows me to write things like

sqrt(2)

and know I get a far more readable equivalent to Chapel's sqrt_2 for the same zero run-time overhead and without cluttering up the name space with all these extra symbols. So, what you are proposing with IntMath might break what I do.

damianmoz commented 4 months ago

Tom, I will send you a fix to make the "surprising" out of the behaviour. But later today (your time). It will give you (almost) the behaviour of Haskell which you said you are happy with.

damianmoz commented 4 months ago

Tom. Stick

inline proc sqrt(param x : int(?w), type T = real(64)) param
{
    param A002193 = 1.4142135623730950488016887242096980785696718753;

    if x == 0 || x == 1 then
        return x:T;
    else if x != 2 then
        compilerError("Only sqrt(0) or sqrt(1) or sqrt(2) is supported");

    return A002193:T;
}
inline proc sqrt(x : int(?w), type T = real(64))
{
    return sqrt(x:T);
}

somewhere your program can find it, e.g. in some master include file of your own, or maybe AutoMath,chpl.

Once you are compiling with the above being pulled in appropriately, the only integral expressions fed to sqrt() that the Chapel compiler will now accept are either a) a compile-time integral expression which evaluates to either 0 or 1 or 2, anything else is rejected b a run-time integral expression which by default is cast to a real(64) expression unless you tell it otherwise.

If you want a compile-time positive integral expression which exceeds 2, then cast it yourself to stop the compiler error:

sqrt(493:real(64));

If you are wondering where that funny variable name came from, see OEIS.org

@bradcray or @mppf will probably have wiser words on how best to incorporate these two procs into your own program.

twesterhout commented 4 months ago

@damianmoz thanks for the explanations and the workaround!

@bradcray C99's math.h defines some type-generic macros: https://en.cppreference.com/w/c/numeric/math/sqrt. Bullet point 4 there says:

If arg has type long double, sqrtl is called. Otherwise, if arg has integer type or the type double, sqrt is called. Otherwise, sqrtf is called. If arg is complex or imaginary, then the macro invokes the corresponding complex function (csqrtf, csqrt, csqrtl).

damianmoz commented 4 months ago

Written in Chapel-ese, those C rules preclude type promotion of an int(w) where w < 64 to anything other than than an real(64) when used with C's type-generic macros. Chapel's rules are simpler, are concurrently both more flexible and more rigorous, and are more orthogonal. And as you can see from what I sent you, those same rules can also be used to provide the C++ functionality (or that of tgmath.h of C) without affecting those of us who deliberately do not want such type promotion. The procs I sent you were more than a workaround. It is an enhancement built on top of Chapel using the powerful features of Chapel that still obeys all the Chapel type mixing rules.

mppf commented 4 months ago

I'm looking at adding a warning. There are two ways I could implement the warning:

  1. We warn if the call chosen in the process of overload resolution does an implicit conversion from int/uint to real/complex that changes the width, unless it's going to the default width (64)
  2. We warn during overload resolution, so that we only warn in cases when there are overloads with multiple real / complex widths (e.g. with proc sqrt(x: real(32) and proc sqrt(x: real(64)), but otherwise the same rule as above (not warning for the same width or if it converts to the default width).

At first, I was thinking that (2) would be better (by making the warning less likely to appear in cases where it doesn't matter) but it seems that, if we were to add proc sqrt overloads for real(8) and real(16) (supposing that those are implemented; today they are not) then @twesterhout would still want to see a warning for something like sqrt(myInt16) rather than ending up with a real(16) result.

Any thoughts on which of these (or some other rule) would be better?

damianmoz commented 4 months ago

Something to ponder deeply over the weekend. Thanks for that,

damianmoz commented 4 months ago

I know I do not have enough experience in working with real(16).

For now I would go with the simplest one to implement and then Tom and others see how well it works. If it needs refinement, then so be it. I am sure it will.I think it will only get tested thoroughly when it is used on hardware which implements IEEE 754 binary16 and a version of Chapel that knows how to exploit it.

bradcray commented 4 months ago

@twesterhout:

@bradcray C99's math.h defines some type-generic macros: https://en.cppreference.com/w/c/numeric/math/sqrt.

Thanks for pointing that out. This still doesn't quite feel like the same thing to me since it isn't choosing between a float vs. double overload of the routine. It also seems likely it was made to work this way due to the need for backward compatibility since sqrt(my32BitFloat) would have called sqrt(double arg) in traditional C prior to this macro's addition, and that behavior presumably had to be retained after the macro was added (whereas sqrt(myLongDouble) would never have resolved to sqrt(double arg) so could be added without breaking existing code).

bradcray commented 4 months ago

@mppf: Either of the two warnings seem reasonable and helpful to me. I'll be curious for Tom's thoughts as well as the impact (of either) on existing code in our testing system.

mppf commented 4 months ago

@mppf: Either of the two warnings seem reasonable and helpful to me. I'll be curious for Tom's thoughts as well as the impact (of either) on existing code in our testing system.

I've run testing on a prototype implementation of (1) and see 63 failures.

``` [Cleaning file /chapel/home/mferguson/w/1/test/deprecated/random/RandomStreamInterface/choiceTestArray.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean choiceTestArray.chpl Mon Mar 04 09:20:20 CST 2024] [Starting sub_clean - Mon Mar 04 09:20:20 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/deprecated/random/RandomStreamInterface] Cleaning test: choiceTestArray [Working on file choiceTestArray.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:20:20 CST 2024] [Starting subtest - Mon Mar 04 09:20:22 CST 2024] [test: deprecated/random/RandomStreamInterface/choiceTestArray.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o choiceTestArray --cc-warnings choiceTestArray.chpl < /dev/null] [Elapsed compilation time for "deprecated/random/RandomStreamInterface/choiceTestArray" - 15.731 seconds] [Success compiling deprecated/random/RandomStreamInterface/choiceTestArray] [Executing program ./choiceTestArray < /dev/null] [Elapsed execution time for "deprecated/random/RandomStreamInterface/choiceTestArray" - 4.914 seconds] [Executing ./PREDIFF] [Executing diff choiceTestArray.good choiceTestArray.exec.out.tmp] 59a60,61 > $CHPL_HOME/modules/standard/Random.chpl:nnnn: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/standard/Random.chpl:nnnn: note: add a cast :real(32) to avoid this warning 130a133,134 > choiceTestArray.chpl:40: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > choiceTestArray.chpl:40: note: add a cast :real(32) to avoid this warning [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestArray] [Elapsed time to compile and execute all versions of "deprecated/random/RandomStreamInterface/choiceTestArray" - 20.689 seconds] [Finished subtest "deprecated/random/RandomStreamInterface/choiceTestArray" - 22.378 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/deprecated/random/RandomStreamInterface/choiceTestDomain.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean choiceTestDomain.chpl Mon Mar 04 09:20:43 CST 2024] [Starting sub_clean - Mon Mar 04 09:20:43 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/deprecated/random/RandomStreamInterface] Cleaning test: choiceTestDomain [Working on file choiceTestDomain.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:20:43 CST 2024] [Starting subtest - Mon Mar 04 09:20:45 CST 2024] [test: deprecated/random/RandomStreamInterface/choiceTestDomain.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o choiceTestDomain --cc-warnings choiceTestDomain.chpl < /dev/null] [Elapsed compilation time for "deprecated/random/RandomStreamInterface/choiceTestDomain" - 13.446 seconds] [Success compiling deprecated/random/RandomStreamInterface/choiceTestDomain] [Executing program ./choiceTestDomain < /dev/null] [Elapsed execution time for "deprecated/random/RandomStreamInterface/choiceTestDomain" - 2.896 seconds] [Executing ./PREDIFF] [Executing diff choiceTestDomain.good choiceTestDomain.exec.out.tmp] 73a74,75 > $CHPL_HOME/modules/standard/Random.chpl:nnnn: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/standard/Random.chpl:nnnn: note: add a cast :real(32) to avoid this warning 117a120,121 > choiceTestDomain.chpl:29: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > choiceTestDomain.chpl:29: note: add a cast :real(32) to avoid this warning [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestDomain] [Elapsed time to compile and execute all versions of "deprecated/random/RandomStreamInterface/choiceTestDomain" - 16.385 seconds] [Finished subtest "deprecated/random/RandomStreamInterface/choiceTestDomain" - 18.160 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/deprecated/random/RandomStreamInterface/choiceTestRange.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean choiceTestRange.chpl Mon Mar 04 09:21:01 CST 2024] [Starting sub_clean - Mon Mar 04 09:21:01 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/deprecated/random/RandomStreamInterface] Cleaning test: choiceTestRange [Working on file choiceTestRange.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:21:02 CST 2024] [Starting subtest - Mon Mar 04 09:21:03 CST 2024] [test: deprecated/random/RandomStreamInterface/choiceTestRange.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o choiceTestRange --cc-warnings choiceTestRange.chpl < /dev/null] [Elapsed compilation time for "deprecated/random/RandomStreamInterface/choiceTestRange" - 13.240 seconds] [Success compiling deprecated/random/RandomStreamInterface/choiceTestRange] [Executing program ./choiceTestRange < /dev/null] [Elapsed execution time for "deprecated/random/RandomStreamInterface/choiceTestRange" - 2.975 seconds] [Executing ./PREDIFF] [Executing diff choiceTestRange.good choiceTestRange.exec.out.tmp] 73a74,75 > $CHPL_HOME/modules/standard/Random.chpl:nnnn: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/standard/Random.chpl:nnnn: note: add a cast :real(32) to avoid this warning 117a120,121 > choiceTestRange.chpl:29: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > choiceTestRange.chpl:29: note: add a cast :real(32) to avoid this warning [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestRange] [Elapsed time to compile and execute all versions of "deprecated/random/RandomStreamInterface/choiceTestRange" - 16.257 seconds] [Finished subtest "deprecated/random/RandomStreamInterface/choiceTestRange" - 17.959 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/distributions/robust/associative/basic/array_iter.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean array_iter.chpl Mon Mar 04 09:21:20 CST 2024] [Starting sub_clean - Mon Mar 04 09:21:20 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/distributions/robust/associative/basic] Cleaning test: array_iter [Working on file array_iter.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:21:20 CST 2024] [Starting subtest - Mon Mar 04 09:21:22 CST 2024] [test: distributions/robust/associative/basic/array_iter.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o array_iter --cc-warnings -M.. -snoParSafeWarning array_iter.chpl < /dev/null] [Elapsed compilation time for "distributions/robust/associative/basic/array_iter (compopts: 1)" - 10.658 seconds] [Success compiling distributions/robust/associative/basic/array_iter] [Executing program ./array_iter < /dev/null] [Elapsed execution time for "distributions/robust/associative/basic/array_iter (compopts: 1)" - 0.187 seconds] [Executing diff array_iter.good array_iter.exec.out.tmp] 0a1,8 > array_iter.chpl:64: In function 'testSerial': > array_iter.chpl:69: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > array_iter.chpl:69: note: add a cast :real(32) to avoid this warning > array_iter.chpl:57: called as testSerial(AAssoc: [DefaultAssociativeDom(real(32),false)] real(32), D: domain(1,int(64),one), Arr: [domain(1,int(64),one)] real(32), ArrRef: [domain(1,int(64),one)] real(32)) > array_iter.chpl:90: In function 'testParallel': > array_iter.chpl:95: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > array_iter.chpl:95: note: add a cast :real(32) to avoid this warning > array_iter.chpl:58: called as testParallel(AAssoc: [DefaultAssociativeDom(real(32),false)] real(32), D: domain(1,int(64),one), Arr: [domain(1,int(64),one)] real(32), ArrRef: [domain(1,int(64),one)] real(32)) [Error matching program output for distributions/robust/associative/basic/array_iter] [Elapsed time to compile and execute all versions of "distributions/robust/associative/basic/array_iter" - 10.863 seconds] [Finished subtest "distributions/robust/associative/basic/array_iter" - 13.190 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/distributions/robust/associative/basic/domain_iter.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean domain_iter.chpl Mon Mar 04 09:21:33 CST 2024] [Starting sub_clean - Mon Mar 04 09:21:33 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/distributions/robust/associative/basic] Cleaning test: domain_iter [Working on file domain_iter.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:21:33 CST 2024] [Starting subtest - Mon Mar 04 09:21:36 CST 2024] [test: distributions/robust/associative/basic/domain_iter.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o domain_iter --cc-warnings -M.. -snoParSafeWarning domain_iter.chpl < /dev/null] [Elapsed compilation time for "distributions/robust/associative/basic/domain_iter (compopts: 1)" - 11.151 seconds] [Success compiling distributions/robust/associative/basic/domain_iter] [Executing program ./domain_iter < /dev/null] [Elapsed execution time for "distributions/robust/associative/basic/domain_iter (compopts: 1)" - 0.186 seconds] [Executing diff domain_iter.good domain_iter.exec.out.tmp] 0a1,8 > domain_iter.chpl:49: In function 'testSerial': > domain_iter.chpl:53: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > domain_iter.chpl:53: note: add a cast :real(32) to avoid this warning > domain_iter.chpl:42: called as testSerial(Dom: DefaultAssociativeDom(real(32),false), D: domain(1,int(64),one), Arr: [domain(1,int(64),one)] real(32), ArrRef: [domain(1,int(64),one)] real(32)) > domain_iter.chpl:74: In function 'testParallel': > domain_iter.chpl:78: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > domain_iter.chpl:78: note: add a cast :real(32) to avoid this warning > domain_iter.chpl:43: called as testParallel(Dom: DefaultAssociativeDom(real(32),false), D: domain(1,int(64),one), Arr: [domain(1,int(64),one)] real(32), ArrRef: [domain(1,int(64),one)] real(32)) [Error matching program output for distributions/robust/associative/basic/domain_iter] [Elapsed time to compile and execute all versions of "distributions/robust/associative/basic/domain_iter" - 11.354 seconds] [Finished subtest "distributions/robust/associative/basic/domain_iter" - 13.732 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/functions/ferguson/coercions.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean coercions.chpl Mon Mar 04 09:21:47 CST 2024] [Starting sub_clean - Mon Mar 04 09:21:47 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/functions/ferguson] Cleaning test: coercions [Working on file coercions.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:21:47 CST 2024] [Starting subtest - Mon Mar 04 09:21:49 CST 2024] [test: functions/ferguson/coercions.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o coercions --cc-warnings --no-overload-sets-checks coercions.chpl < /dev/null] [Elapsed compilation time for "functions/ferguson/coercions (compopts: 1)" - 6.503 seconds] [Success compiling functions/ferguson/coercions] [Executing program ./coercions < /dev/null] [Elapsed execution time for "functions/ferguson/coercions (compopts: 1)" - 0.087 seconds] [Executing diff coercions.good coercions.exec.out.tmp] 0a1,30 > coercions.chpl:82: In function 'test0': > coercions.chpl:86: warning: potentially surprising implicit conversion from 'uint(8)' to 'real(32)' > coercions.chpl:86: note: add a cast :real(32) to avoid this warning > coercions.chpl:88: warning: potentially surprising implicit conversion from 'int(8)' to 'real(32)' > coercions.chpl:88: note: add a cast :real(32) to avoid this warning > coercions.chpl:90: warning: potentially surprising implicit conversion from 'uint(16)' to 'real(32)' > coercions.chpl:90: note: add a cast :real(32) to avoid this warning > coercions.chpl:92: warning: potentially surprising implicit conversion from 'int(16)' to 'real(32)' > coercions.chpl:92: note: add a cast :real(32) to avoid this warning > coercions.chpl:114: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions.chpl:114: note: add a cast :real(32) to avoid this warning > coercions.chpl:116: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions.chpl:116: note: add a cast :real(32) to avoid this warning > coercions.chpl:118: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions.chpl:118: note: add a cast :real(32) to avoid this warning > coercions.chpl:120: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions.chpl:120: note: add a cast :real(32) to avoid this warning > coercions.chpl:122: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions.chpl:122: note: add a cast :real(32) to avoid this warning > coercions.chpl:124: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions.chpl:124: note: add a cast :real(32) to avoid this warning > coercions.chpl:144: In function 'test1': > coercions.chpl:148: warning: potentially surprising implicit conversion from 'uint(8)' to 'real(32)' > coercions.chpl:148: note: add a cast :real(32) to avoid this warning > coercions.chpl:150: warning: potentially surprising implicit conversion from 'int(8)' to 'real(32)' > coercions.chpl:150: note: add a cast :real(32) to avoid this warning > coercions.chpl:152: warning: potentially surprising implicit conversion from 'uint(16)' to 'real(32)' > coercions.chpl:152: note: add a cast :real(32) to avoid this warning > coercions.chpl:154: warning: potentially surprising implicit conversion from 'int(16)' to 'real(32)' > coercions.chpl:154: note: add a cast :real(32) to avoid this warning [Error matching program output for functions/ferguson/coercions] [Elapsed time to compile and execute all versions of "functions/ferguson/coercions" - 6.608 seconds] [Finished subtest "functions/ferguson/coercions" - 8.703 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/functions/ferguson/coercions-5922.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean coercions-5922.chpl Mon Mar 04 09:21:56 CST 2024] [Starting sub_clean - Mon Mar 04 09:21:56 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/functions/ferguson] Cleaning test: coercions-5922 [Working on file coercions-5922.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:21:56 CST 2024] [Starting subtest - Mon Mar 04 09:21:58 CST 2024] [test: functions/ferguson/coercions-5922.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o coercions-5922 --cc-warnings coercions-5922.chpl < /dev/null] [Elapsed compilation time for "functions/ferguson/coercions-5922" - 5.294 seconds] [Success compiling functions/ferguson/coercions-5922] [Executing program ./coercions-5922 < /dev/null] [Elapsed execution time for "functions/ferguson/coercions-5922" - 0.094 seconds] [Executing diff coercions-5922.good coercions-5922.exec.out.tmp] 0a1,4 > coercions-5922.chpl:2: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions-5922.chpl:2: note: add a cast :real(32) to avoid this warning > coercions-5922.chpl:2: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > coercions-5922.chpl:2: note: add a cast :real(32) to avoid this warning [Error matching program output for functions/ferguson/coercions-5922] [Elapsed time to compile and execute all versions of "functions/ferguson/coercions-5922" - 5.406 seconds] [Finished subtest "functions/ferguson/coercions-5922" - 7.168 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/io/jhh/readbinary.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean readbinary.chpl Mon Mar 04 09:22:04 CST 2024] [Starting sub_clean - Mon Mar 04 09:22:04 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/io/jhh] Cleaning test: readbinary [Working on file readbinary.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:22:04 CST 2024] [Starting subtest - Mon Mar 04 09:22:06 CST 2024] [test: io/jhh/readbinary.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o readbinary --cc-warnings readbinary.chpl < /dev/null] [Elapsed compilation time for "io/jhh/readbinary" - 5.922 seconds] [Success compiling io/jhh/readbinary] [Executing program ./readbinary < readbinary.stdin] [Elapsed execution time for "io/jhh/readbinary" - 0.092 seconds] [Executing diff readbinary.good readbinary.exec.out.tmp] 0a1,8 > $CHPL_HOME/modules/internal/StringCasts.chpl:258: In function ':': > $CHPL_HOME/modules/internal/StringCasts.chpl:264: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/internal/StringCasts.chpl:264: note: add a cast :real(32) to avoid this warning > $CHPL_HOME/modules/internal/ChapelIOStringifyHelper.chpl:94: called as :(x: complex(64), type t = string) > within internal functions (use --print-callstack-on-error to see) > readbinary.chpl:28: called as assert(test: bool, args(0): string, args(1): complex(64), args(2): complex(64)) from function 'readone' > readbinary.chpl:33: called as readone(expected: complex(64), endian: endianness) from function 'readall' > readbinary.chpl:55: called as readall(expected: complex(64)) [Error matching program output for io/jhh/readbinary] [Elapsed time to compile and execute all versions of "io/jhh/readbinary" - 6.029 seconds] [Finished subtest "io/jhh/readbinary" - 7.752 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/library/packages/LinearAlgebra/correctness/no-dependencies/correctness.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean correctness.chpl Mon Mar 04 09:22:12 CST 2024] [Starting sub_clean - Mon Mar 04 09:22:12 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/library/packages/LinearAlgebra/correctness/no-dependencies] Cleaning test: correctness [Working on file correctness.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:22:12 CST 2024] [Starting subtest - Mon Mar 04 09:22:14 CST 2024] [test: library/packages/LinearAlgebra/correctness/no-dependencies/correctness.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o correctness --cc-warnings --set blasImpl=off --set lapackImpl=off -M ../ correctness.chpl < /dev/null] [Elapsed compilation time for "library/packages/LinearAlgebra/correctness/no-dependencies/correctness (compopts: 1)" - 25.696 seconds] [Success compiling library/packages/LinearAlgebra/correctness/no-dependencies/correctness] [Executing program ./correctness < /dev/null] [Elapsed execution time for "library/packages/LinearAlgebra/correctness/no-dependencies/correctness (compopts: 1)" - 0.255 seconds] [Executing diff correctness.good correctness.exec.out.tmp] 0a1,14 > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:1101: In function '_matmatMultHelper': > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:1140: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:1140: note: add a cast :real(32) to avoid this warning > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:1081: called as _matmatMultHelper(AMat: [domain(2,int(64),one)] real(32), BMat: [domain(2,int(64),one)] real(32), CMat: [domain(2,int(64),one)] real(32)) from function '_matmatMult' > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:894: called as _matmatMult(A: [domain(2,int(64),one)] real(32), B: [domain(2,int(64),one)] real(32)) from function 'matMult' > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:850: called as matMult(A: [domain(2,int(64),one)] real(32), B: [domain(2,int(64),one)] real(32)) from function 'dot' > correctness.chpl:252: called as dot(A: [domain(2,int(64),one)] real(32), B: [domain(2,int(64),one)] real(32)) from function 'test_dot' > correctness.chpl:294: called as test_dot(type t = real(32)) > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:972: In function 'inner': > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:978: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:978: note: add a cast :real(32) to avoid this warning > $CHPL_HOME/modules/packages/LinearAlgebra.chpl:847: called as inner(A: [domain(1,int(64),one)] real(32), B: [domain(1,int(64),one)] real(32)) from function 'dot' > correctness.chpl:265: called as dot(A: [domain(1,int(64),one)] real(32), B: [domain(1,int(64),one)] real(32)) from function 'test_dot' > correctness.chpl:294: called as test_dot(type t = real(32)) [Error matching program output for library/packages/LinearAlgebra/correctness/no-dependencies/correctness] [Elapsed time to compile and execute all versions of "library/packages/LinearAlgebra/correctness/no-dependencies/correctness" - 25.970 seconds] [Finished subtest "library/packages/LinearAlgebra/correctness/no-dependencies/correctness" - 27.971 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/library/standard/AutoMath/absparams.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean absparams.chpl Mon Mar 04 09:22:40 CST 2024] [Starting sub_clean - Mon Mar 04 09:22:40 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/library/standard/AutoMath] Cleaning test: absparams [Working on file absparams.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:22:40 CST 2024] [Starting subtest - Mon Mar 04 09:22:42 CST 2024] [test: library/standard/AutoMath/absparams.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o absparams --cc-warnings absparams.chpl < /dev/null] [Elapsed compilation time for "library/standard/AutoMath/absparams" - 5.970 seconds] [Success compiling library/standard/AutoMath/absparams] [Executing program ./absparams < /dev/null] [Elapsed execution time for "library/standard/AutoMath/absparams" - 0.089 seconds] [Executing diff absparams.good absparams.exec.out.tmp] 0a1,16 > absparams.chpl:21: In function 'testabs': > absparams.chpl:26: warning: potentially surprising implicit conversion from 'uint(8)' to 'real(32)' > absparams.chpl:26: note: add a cast :real(32) to avoid this warning > absparams.chpl:1: called as testabs(param x = 1: uint(8)) > absparams.chpl:21: In function 'testabs': > absparams.chpl:26: warning: potentially surprising implicit conversion from 'uint(16)' to 'real(32)' > absparams.chpl:26: note: add a cast :real(32) to avoid this warning > absparams.chpl:2: called as testabs(param x = 1: uint(16)) > absparams.chpl:21: In function 'testabs': > absparams.chpl:26: warning: potentially surprising implicit conversion from 'int(8)' to 'real(32)' > absparams.chpl:26: note: add a cast :real(32) to avoid this warning > absparams.chpl:6: called as testabs(param x = 1: int(8)) > absparams.chpl:21: In function 'testabs': > absparams.chpl:26: warning: potentially surprising implicit conversion from 'int(16)' to 'real(32)' > absparams.chpl:26: note: add a cast :real(32) to avoid this warning > absparams.chpl:7: called as testabs(param x = 1: int(16)) [Error matching program output for library/standard/AutoMath/absparams] [Elapsed time to compile and execute all versions of "library/standard/AutoMath/absparams" - 6.076 seconds] [Finished subtest "library/standard/AutoMath/absparams" - 7.986 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/library/standard/AutoMath/sqrtparams.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean sqrtparams.chpl Mon Mar 04 09:22:49 CST 2024] [Starting sub_clean - Mon Mar 04 09:22:49 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/library/standard/AutoMath] Cleaning test: sqrtparams [Working on file sqrtparams.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:22:49 CST 2024] [Starting subtest - Mon Mar 04 09:22:51 CST 2024] [test: library/standard/AutoMath/sqrtparams.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o sqrtparams --cc-warnings sqrtparams.chpl < /dev/null] [Elapsed compilation time for "library/standard/AutoMath/sqrtparams" - 5.275 seconds] [Success compiling library/standard/AutoMath/sqrtparams] [Executing program ./sqrtparams < /dev/null] [Elapsed execution time for "library/standard/AutoMath/sqrtparams" - 0.081 seconds] [Executing diff sqrtparams.good sqrtparams.exec.out.tmp] 1a2,5 > sqrtparams.chpl:35: In function 'testsqrt': > sqrtparams.chpl:42: warning: potentially surprising implicit conversion from 'uint(8)' to 'real(32)' > sqrtparams.chpl:42: note: add a cast :real(32) to avoid this warning > sqrtparams.chpl:2: called as testsqrt(param x = 1: uint(8)) 2a7,10 > sqrtparams.chpl:35: In function 'testsqrt': > sqrtparams.chpl:42: warning: potentially surprising implicit conversion from 'uint(16)' to 'real(32)' > sqrtparams.chpl:42: note: add a cast :real(32) to avoid this warning > sqrtparams.chpl:3: called as testsqrt(param x = 1: uint(16)) 5a14,17 > sqrtparams.chpl:35: In function 'testsqrt': > sqrtparams.chpl:42: warning: potentially surprising implicit conversion from 'int(8)' to 'real(32)' > sqrtparams.chpl:42: note: add a cast :real(32) to avoid this warning > sqrtparams.chpl:9: called as testsqrt(param x = 1: int(8)) 6a19,22 > sqrtparams.chpl:35: In function 'testsqrt': > sqrtparams.chpl:42: warning: potentially surprising implicit conversion from 'int(16)' to 'real(32)' > sqrtparams.chpl:42: note: add a cast :real(32) to avoid this warning > sqrtparams.chpl:10: called as testsqrt(param x = 1: int(16)) [Error matching program output for library/standard/AutoMath/sqrtparams] [Elapsed time to compile and execute all versions of "library/standard/AutoMath/sqrtparams" - 5.373 seconds] [Finished subtest "library/standard/AutoMath/sqrtparams" - 7.199 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/library/standard/Math/log10.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean log10.chpl Mon Mar 04 09:22:56 CST 2024] [Starting sub_clean - Mon Mar 04 09:22:56 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/library/standard/Math] Cleaning test: log10 [Working on file log10.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:22:56 CST 2024] [Starting subtest - Mon Mar 04 09:22:58 CST 2024] [test: library/standard/Math/log10.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o log10 --cc-warnings log10.chpl < /dev/null] [Elapsed compilation time for "library/standard/Math/log10" - 5.427 seconds] [Success compiling library/standard/Math/log10] [Executing program ./log10 < /dev/null] [Elapsed execution time for "library/standard/Math/log10" - 0.093 seconds] [Executing diff log10.good log10.exec.out.tmp] 0a1,2 > log10.chpl:4: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > log10.chpl:4: note: add a cast :real(32) to avoid this warning [Error matching program output for library/standard/Math/log10] [Elapsed time to compile and execute all versions of "library/standard/Math/log10" - 5.536 seconds] [Finished subtest "library/standard/Math/log10" - 7.349 seconds] [Cleaning file /chapel/home/mferguson/w/1/test/library/standard/Math/y0.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean y0.chpl Mon Mar 04 09:23:04 CST 2024] [Starting sub_clean - Mon Mar 04 09:23:04 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/library/standard/Math] Cleaning test: y0 [Working on file y0.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:23:04 CST 2024] [Starting subtest - Mon Mar 04 09:23:06 CST 2024] [test: library/standard/Math/y0.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o y0 --cc-warnings y0.chpl < /dev/null] [Elapsed compilation time for "library/standard/Math/y0" - 5.456 seconds] [Success compiling library/standard/Math/y0] [Executing program ./y0 < /dev/null] [Elapsed execution time for "library/standard/Math/y0" - 0.093 seconds] [Executing diff y0.good y0.exec.out.tmp] 0a1,11 > $CHPL_HOME/modules/standard/Math.chpl:1358: In function 'y0': > $CHPL_HOME/modules/standard/Math.chpl:1359: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > $CHPL_HOME/modules/standard/Math.chpl:1359: note: add a cast :real(32) to avoid this warning > y0.chpl:25: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > y0.chpl:25: note: add a cast :real(32) to avoid this warning > y0.chpl:26: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > y0.chpl:26: note: add a cast :real(32) to avoid this warning > y0.chpl:27: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > y0.chpl:27: note: add a cast :real(32) to avoid this warning > y0.chpl:29: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > y0.chpl:29: note: add a cast :real(32) to avoid this warning [Error matching program output for library/standard/Math/y0] [Elapsed time to compile and execute all versions of "library/standard/Math/y0" - 5.566 seconds] [Finished subtest "library/standard/Math/y0" - 7.301 seconds] ... [Cleaning file /chapel/home/mferguson/w/1/test/users/bachman/Beta_Diversity/main.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_clean main.chpl Mon Mar 04 09:33:05 CST 2024] [Starting sub_clean - Mon Mar 04 09:33:05 CST 2024] [pwd: /chapel/home/mferguson/w/1/test/users/bachman/Beta_Diversity] Cleaning test: main [Working on file main.chpl] [Starting /chapel/home/mferguson/w/1/util/test/sub_test Mon Mar 04 09:33:05 CST 2024] [Starting subtest - Mon Mar 04 09:33:07 CST 2024] [test: users/bachman/Beta_Diversity/main.chpl] [Executing compiler /chapel/home/mferguson/w/1/bin/linux64-x86_64/chpl -o main --cc-warnings main.chpl < /dev/null] [Elapsed compilation time for "users/bachman/Beta_Diversity/main" - 16.067 seconds] [Success compiling users/bachman/Beta_Diversity/main] [Executing program ./main --in_name=banda_ai --map_type=benthic --window_size=1000 < /dev/null] [Elapsed execution time for "users/bachman/Beta_Diversity/main" - 0.403 seconds] [Executing diff main.good main.exec.out.tmp] 0a1,7 > main.chpl:121: In function 'main': > main.chpl:127: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > main.chpl:127: note: add a cast :real(32) to avoid this warning > main.chpl:128: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > main.chpl:128: note: add a cast :real(32) to avoid this warning > main.chpl:165: warning: potentially surprising implicit conversion from 'int(64)' to 'real(32)' > main.chpl:165: note: add a cast :real(32) to avoid this warning [Error matching program output for users/bachman/Beta_Diversity/main] [Elapsed time to compile and execute all versions of "users/bachman/Beta_Diversity/main" - 16.489 seconds] [Finished subtest "users/bachman/Beta_Diversity/main" - 18.809 seconds] [Done with tests - 240304.093324] [Log file: /chapel/home/mferguson/w/1/test/Logs/mferguson.linux64.log ] [Test Summary - 240304.093324] [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestArray] [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestDomain] [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestRange] [Error matching program output for distributions/robust/associative/basic/array_iter] [Error matching program output for distributions/robust/associative/basic/domain_iter] [Error matching program output for functions/ferguson/coercions] [Error matching program output for functions/ferguson/coercions-5922] [Error matching program output for io/jhh/readbinary] [Error matching program output for library/packages/LinearAlgebra/correctness/no-dependencies/correctness] [Error matching program output for library/standard/AutoMath/absparams] [Error matching program output for library/standard/AutoMath/sqrtparams] [Error matching program output for library/standard/Math/log10] [Error matching program output for library/standard/Math/y0] [Error matching program output for library/standard/Math/y1] [Error matching program output for library/standard/Math/yn] [Error matching program output for parallel/sync/deitz/test_generic_sync] [Error matching program output for param/ferguson/inf-nan-narrowing] [Error matching program output for param/ferguson/param-abs] [Error matching program output for param/ferguson/param-re-im] [Error matching program output for release/examples/primers/records] [Error matching program output for runtime/configMatters/comm/atomics] [Error matching program output for runtime/configMatters/comm/atomics-api] [Error matching program output for runtime/configMatters/comm/atomics-api-on (execopts: 1)] [Error matching program output for runtime/configMatters/comm/atomics-api-on (execopts: 2)] [Error matching program output for runtime/configMatters/comm/peek-poke] [Error matching program output for runtime/configMatters/comm/unordered/unorderedAtomicsApiOn (execopts: 1)] [Error matching program output for runtime/configMatters/comm/unordered/unorderedAtomicsApiOn (execopts: 2)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 1)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 2)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 3)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 4)] [Error matching program output for studies/ml/performance/mnist_cnn_batch] [Error matching program output for studies/ml/performance/mnist_cnn_big_everything] [Error matching program output for studies/ml/performance/mnist_cnn_deep] [Error matching program output for studies/ml/performance/mnist_cnn_no_batch] [Error matching program output for studies/ml/performance/mnist_cnn_no_stride] [Error matching program output for studies/ml/performance/mnist_cnn_stride] [Error matching program output for studies/ml/performance/mnist_cnn_with_dense] [Error matching program output for studies/parboil/histo/histoSerial] [Error matching program output for types/coerce/allNumericsBinary] [Error matching program output for types/coerce/allNumericsBinaryBigParam] [Error matching .bad file for types/coerce/allNumericsBinaryGeneric] [Error matching program output for types/coerce/allNumericsBinaryParam] [Error matching program output for types/coerce/allNumericsBinaryParamParam] [Error matching program output for types/coerce/allNumericsBinaryRealImagComplex-compiles] [Error matching compiler output for types/coerce/allNumericsBinaryRealImagComplex-errors] [Error matching compiler output for types/coerce/allNumericsBinaryWithGeneric] [Error matching program output for types/coerce/allNumericsUnaryRealImagComplex] [Error matching program output for types/coerce/boundaryIntCoerce] [Error matching program output for types/coerce/bradc/printcomplex] [Error matching program output for types/coerce/bradc/printzeroes] [Error matching program output for types/coerce/bradc/tostring] [Error matching program output for types/coerce/intParamCoerce] [Error matching program output for types/coerce/intPlusReal32] [Error matching program output for types/coerce/smallIntCoerce] [Error matching program output for types/coerce/smallIntParamCoerce] [Error matching program output for types/complex/bradc/resultWidths] [Error matching program output for types/scalar/vass/int8toReal32] [Error matching program output for types/scalar/vass/paramInt64ToOtherInts] [Error matching program output for types/string/StringImpl/memLeaks/cast] [Error matching program output for types/string/StringImpl/memLeaks/concat] [Error matching program output for unstable/Math/unstableBessel] [Error matching program output for users/bachman/Beta_Diversity/main] Future (feature request: instantiate generics with implicit conversion) [Error matching program output for types/coerce/allNumericsBinaryGeneric] [Summary: #Successes = 0 | #Failures = 63 | #Futures = 1 | #Warnings = 0 ] [Summary: #Passing Suppressions = 0 | #Passing Futures = 0 ] [END] ```

One case comes up in the record primer & looks like this:

record Color {
  var red: uint(8);
  var green: uint(8);
  var blue: uint(8);
}
proc Color.luminance() {
  return 0.2126*red + 0.7152*green + 0.0722*blue; // warns here
}

Put perhaps there is a variation of (2) that would not warn here, if that is important to us. (perhaps we could limit the warning to cases where the overloads under consideration have differing floating point return types)

twesterhout commented 4 months ago

@mppf thanks for working on this! I'm looking into your warning suggestions, and would warning whenever a conversion occurs from real(w1) to real(w2) with w2 > w1 not just cover all the cases (similar thing with complex(w1)->complex(w2) and with real(w1)->complex(w2))? This would also avoid warning in the above example with Color.

mppf commented 4 months ago

@twesterhout - might be missing something, but I thought the problematic case we are trying to warn for is when implicit converting a a small integer (e.g. int(16)) into real(32) (today) or real(16) etc (in the future).

twesterhout commented 4 months ago

@mppf right, but after reading and thinking about Damian's comments, I'm starting to agree that converting int(16) to real(32) or real(16) isn't bad by itself. What's causing precision loss is when that real(32) number is used in combination with real(64) numbers coming from other sources. E.g. sqrt(x:int(16)) * sin(y:real(64)) is most likely a programmer's error whereas sqrt(x:int(16)) + 2:real(32) seems fine. Does that make sense?

mppf commented 4 months ago

Gotcha. One nice thing about that approach is that it focuses on the floating point part.

Some concerns about it:

Nevertheless, I tried implementing it real quick and running testing with it. I saw 180 failures. So, whether it is good or bad, the pattern of converting real(32) into real(64) occurs more in our tests than the pattern of converting small integers to real(32).

``` [Error matching program output for arrays/literals/hetLiteralsUnifiable] [Error matching program output for chplvis/benchmarks-hpcc/fft-vdb] [Error matching program output for constrained-generics/hashable/hash-numeric] [Error matching program output for deprecated/IO/pcnt_ht_format] [Error matching program output for deprecated/IO/pcnt_jt_format] [Error matching program output for deprecated/IO/pcnt_t_format] [Error matching program output for deprecated/random/RandomStreamInterface/choiceTestArray] [Error matching program output for deprecated/recordiobug] [Error matching program output for distributions/robust/associative/basic/array_iter] [Error matching program output for distributions/robust/associative/basic/array_write] [Error matching program output for distributions/robust/associative/basic/domain_iter] [Error matching program output for distributions/robust/associative/basic/domain_write] [Error matching program output for distributions/robust/associative/basic/promotion] [Error matching program output for distributions/robust/associative/basic/reduce] [Error matching program output for distributions/robust/associative/basic/whole_array_assign] [Error matching program output for distributions/robust/associative/basic/whole_domain_assign] [Error matching program output for distributions/robust/associative/basic/zipper] [Error matching program output for distributions/robust/associative/stress/many_array] [Error matching program output for domains/sungeun/assoc/equality (compopts: 1)] [Error matching program output for domains/sungeun/assoc/equality (compopts: 2)] [Error matching program output for domains/sungeun/assoc/equality (compopts: 11)] [Error matching program output for domains/sungeun/assoc/equality (compopts: 12)] [Error matching program output for execflags/diten/configComplex] [Error matching program output for exercises/wavelet/wavelet] [Error matching program output for functions/ferguson/coercions] [Error matching program output for functions/intents/out/out-intent-type-from-fn] [Error matching compiler output for functions/iterators/bugs/list-from-iter-no-default-init-compiles] [Error matching program output for io/ferguson/assoc-array-chpl] [Error matching program output for io/ferguson/digits (execopts: 1)] [Error matching program output for io/ferguson/digits (execopts: 2)] [Error matching program output for io/ferguson/digits (execopts: 3)] [Error matching program output for io/ferguson/digits (execopts: 4)] [Error matching program output for io/ferguson/enum-with-prefix] [Error matching program output for io/ferguson/issue-16945] [Error matching program output for io/ferguson/issue-18156] [Error matching program output for io/ferguson/json-basic] [Error matching program output for io/ferguson/json-distributed-arrays] [Error matching program output for io/ferguson/json-enum] [Error matching program output for io/ferguson/json-linked-list] [Error matching program output for io/ferguson/json-linked-list2] [Error matching program output for io/ferguson/json-list] [Error matching program output for io/ferguson/json-list2] [Error matching program output for io/ferguson/scanstring-precision] [Error matching program output for io/ferguson/writef_readf (compopts: 1)] [Error matching program output for io/ferguson/writef_readf (compopts: 2)] [Error matching program output for io/stonea/readDifferentRankArrays] [Error matching program output for io/recordio] [Error matching program output for library/packages/LinearAlgebra/correctness/no-dependencies/correctness-Sparse-import] [Error matching program output for library/packages/LinearAlgebra/correctness/no-dependencies/correctness] [Error matching program output for library/packages/LinearAlgebra/correctness/no-dependencies/testExpm] [Error matching program output for library/packages/LinearAlgebra/performance/me/me-perf] [Error matching program output for library/packages/MatrixMarket/complexspwtst] [Error matching program output for library/packages/MatrixMarket/complextst] [Error matching program output for library/packages/MatrixMarket/mm-read-dense (execopts: 1)] [Error matching program output for library/packages/MatrixMarket/mm-read-dense (execopts: 2)] [Error matching program output for library/packages/MatrixMarket/mm-read-dense (execopts: 3)] [Error matching program output for library/packages/MatrixMarket/mm-read-dense (execopts: 4)] [Error matching program output for library/packages/MatrixMarket/mm-read-sparse (execopts: 1)] [Error matching program output for library/packages/MatrixMarket/mm-read-sparse (execopts: 2)] [Error matching program output for library/packages/MatrixMarket/mm-read-sparse (execopts: 3)] [Error matching program output for library/packages/MatrixMarket/mm-read-sparse (execopts: 4)] [Error matching program output for library/packages/MatrixMarket/realtst] [Error matching program output for library/packages/MatrixMarket/realwtst] [Error matching program output for library/packages/Sort/correctness/sortReal] [Error matching program output for library/packages/UnitTest/AssertEqual/AssertEqualTest] [Error matching program output for library/packages/UnitTest/AssertNotEqual/AssertNotEqualTest] [Error matching .bad file for library/packages/Yaml/percent-q] [Error matching compiler output for library/packages/canCompileNoLink/BLAStest] [Error matching program output for library/standard/AutoMath/sqrtparams] [Error matching program output for library/standard/IO/formatted/serde_specifier] [Error matching program output for library/standard/List/testJson] [Error matching program output for library/standard/Map/testJson] [Error matching program output for library/standard/Math/fma] [Error matching program output for param/ferguson/param-abs] [Error matching program output for param/ferguson/param-re-im] [Error matching program output for param/ferguson/param-sqrt] [Error matching program output for performance/compiler/bradc/fft-timecomp] [Error matching program output for regex/bytes/nonUTFIO (execopts: 1)] [Error matching program output for regex/bytes/nonUTFIO (execopts: 2)] [Error matching program output for regex/ferguson/bug-16891] [Error matching program output for regex/ferguson/readfinf] [Error matching program output for regex/ferguson/readfre (compopts: 1)] [Error matching program output for regex/ferguson/readfre (compopts: 2)] [Error matching program output for runtime/configMatters/comm/atomic-stress-multi] [Error matching program output for runtime/configMatters/comm/atomic-stress] [Error matching program output for runtime/configMatters/comm/atomics] [Error matching program output for studies/adventOfCode/2021/bradc/day13 (execopts: 1)] [Error matching program output for studies/adventOfCode/2021/bradc/day13 (execopts: 2)] [Error matching program output for studies/adventOfCode/2021/bradc/day19] [Error matching program output for studies/adventOfCode/2021/bradc/day19a] [Error matching program output for studies/adventOfCode/2021/bradc/day22 (execopts: 1)] [Error matching program output for studies/adventOfCode/2021/bradc/day22 (execopts: 2)] [Error matching program output for studies/adventOfCode/2021/bradc/day22 (execopts: 3)] [Error matching program output for studies/adventOfCode/2021/bradc/day22a] [Error matching program output for studies/adventOfCode/2021/bradc/day3 (execopts: 1)] [Error matching program output for studies/adventOfCode/2021/bradc/day3 (execopts: 2)] [Error matching program output for studies/adventOfCode/2021/bradc/day3a (execopts: 1)] [Error matching program output for studies/adventOfCode/2021/bradc/day3a (execopts: 2)] [Error matching program output for studies/adventOfCode/2021/bradc/day5 (execopts: 1)] [Error matching program output for studies/adventOfCode/2021/bradc/day5 (execopts: 2)] [Error matching program output for studies/adventOfCode/2021/bradc/day5a (execopts: 1)] [Error matching program output for studies/adventOfCode/2021/bradc/day5a (execopts: 2)] [Error matching program output for studies/adventOfCode/2022/bugs/day05] [Error matching program output for studies/adventOfCode/2022/day02/bradc/day02] [Error matching program output for studies/adventOfCode/2022/day02/bradc/day02a] [Error matching program output for studies/adventOfCode/2022/day04/bradc/day04-mms-inspired] [Error matching program output for studies/adventOfCode/2022/day04/bradc/day04-mms-with-forall] [Error matching program output for studies/adventOfCode/2022/day05/bradc/day05] [Error matching program output for studies/adventOfCode/2022/day05/bradc/day05a] [Error matching program output for studies/adventOfCode/2022/day09/jeremiah/day9a] [Error matching program output for studies/adventOfCode/2022/day09/jeremiah/day9b] [Error matching program output for studies/adventOfCode/2022/day11/bradc/day11 (execopts: 1)] [Error matching program output for studies/adventOfCode/2022/day11/bradc/day11 (execopts: 2)] [Error matching program output for studies/adventOfCode/2022/day11/bradc/day11a (execopts: 1)] [Error matching program output for studies/adventOfCode/2022/day11/bradc/day11a (execopts: 2)] [Error matching program output for studies/dedup/dedup-distributed-ints] [Error matching program output for studies/dedup/dedup-local] [Error matching program output for studies/hpcc/FFT/bradc/fft-badtuple] [Error matching program output for studies/hpcc/FFT/bradc/fft] [Error matching program output for studies/hpcc/FFT/bradc/twiddles-onebased] [Error matching program output for studies/hpcc/FFT/bradc/twiddles] [Error matching program output for studies/hpcc/FFT/diten/fft] [Error matching program output for studies/hpcc/FFT/marybeth/fft-test-even] [Error matching program output for studies/hpcc/FFT/marybeth/fft] [Error matching program output for studies/hpcc/FFT/marybeth/fft2d] [Error matching program output for studies/hpcc/FFT/fft-candidate-2d] [Error matching program output for studies/hpcc/FFT/fft-hpcc06-mta] [Error matching program output for studies/hpcc/FFT/fft-hpcc06] [Error matching program output for studies/hpcc/FFT/fft-testPow4] [Error matching program output for studies/hpcc/FFT/fft] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 1)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 2)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 3)] [Error matching program output for studies/ml/correctness/mnist_classification (compopts: 4)] [Error matching program output for studies/ml/performance/mnist_cnn_batch] [Error matching program output for studies/ml/performance/mnist_cnn_big_everything] [Error matching program output for studies/ml/performance/mnist_cnn_deep] [Error matching program output for studies/ml/performance/mnist_cnn_no_batch] [Error matching program output for studies/ml/performance/mnist_cnn_no_stride] [Error matching program output for studies/ml/performance/mnist_cnn_stride] [Error matching program output for studies/ml/performance/mnist_cnn_with_dense] [Error matching program output for studies/parboil/histo/histoSerial] [Error matching program output for studies/shootout/mandelbrot/jacobnelson/mandelbrot-complex] [Error matching program output for studies/shootout/mandelbrot/jacobnelson/mandelbrot-dist] [Error matching program output for trivial/waynew/float32-64] [Error matching program output for types/atomic/vass/initialize-atomics-3] [Error matching program output for types/bytes/io/json-io] [Error matching program output for types/bytes/io/read_binary] [Error matching program output for types/bytes/io/read_text] [Error matching program output for types/bytes/io/readwrite-nonutf8-binary] [Error matching program output for types/bytes/io/readwrite-null-binary] [Error matching program output for types/bytes/io/writeread-pattern] [Error matching program output for types/bytes/io/writeread-random] [Error matching program output for types/coerce/allNumericsBinary] [Error matching program output for types/coerce/allNumericsBinaryBigParam] [Error matching .bad file for types/coerce/allNumericsBinaryGeneric] [Error matching program output for types/coerce/allNumericsBinaryParam] [Error matching program output for types/coerce/allNumericsBinaryParamParam] [Error matching program output for types/coerce/allNumericsBinaryRealImagComplex-compiles] [Error matching compiler output for types/coerce/allNumericsBinaryWithGeneric] [Error matching program output for types/complex/bradc/negateimaginary] [Error matching program output for types/complex/bradc/resultWidths] [Error matching program output for types/complex/marybeth/complex_expressions] [Error matching program output for types/enum/readAbstractEnum (execopts: 1)] [Error matching program output for types/enum/readAbstractEnum (execopts: 2)] [Error matching program output for types/enum/readAbstractEnum (execopts: 3)] [Error matching program output for types/enum/readAbstractEnum (execopts: 4)] [Error matching program output for types/enum/readAbstractEnum (execopts: 5)] [Error matching program output for types/enum/readAbstractEnum (execopts: 6)] [Error matching program output for types/enum/readEnumsAsVals] [Error matching program output for types/enum/readSemiAbstractEnumAsValue (execopts: 1)] [Error matching program output for types/enum/readSemiAbstractEnumAsValue (execopts: 2)] [Error matching program output for types/enum/readSemiAbstractEnumAsValue (execopts: 3)] [Error matching program output for types/enum/readSemiAbstractEnumAsValue (execopts: 4)] [Error matching program output for types/enum/readSemiAbstractEnumAsValue (execopts: 5)] [Error matching program output for types/enum/readSemiAbstractEnumAsValue (execopts: 6)] [Error matching program output for types/imag/imag-conversion] [Error matching program output for types/string/cassella/cast-from-string] [Error matching program output for unicode/write_read_smile] [Error matching program output for users/bachman/Beta_Diversity/main] [Summary: #Successes = 16964 | #Failures = 180 | #Futures = 914] ```
twesterhout commented 4 months ago

Very cool!

Lastly, in your code example sqrt(x:int(16)) sin(y:real(64)), the programmer's assumption might have been that sqrt(x:int(16)) would result is something of type real(64); and that's where the error is. Since the warning would complain about the call, it might not be as helpful as a warning focused on the implicit conversion from a small integer to a floating point type.

In my opinion this is the biggest drawback, but to be honest, having a warning outweighs the inconvenience of compile-time debugging for me. E.g., I much rather spend a few minutes recompiling my code a few times and let the compiler check my casts than spend those minutes carefully reading the code and making sure I didn't miss anything. But that's subjective.

bradcray commented 4 months ago

@twesterhout : Thinking outside the box for a moment (motivated by feeling nervous about warnings that users don't care about and eventually just start ignoring), is there a world in which tools other than warnings would be a more satisfying way to catch these surprises/misassumptions about what's going on? E.g., a VSCode extension that would tell you the types of the expressions you're typing in such that you'd see real(32) rather than real(64) on sqrt(myInt32)? Or a mode in which the code was spit back out in a strongly typed format?

damianmoz commented 4 months ago

Some of us use vi, make and the compiler an type shell commands all day.

I have never used Visual Studio in my life. Maybe that explains lots of things! :)

When I write C code, it has to pass through a lint tool before I am happy with it although I sometimes allow the lint tool to relax some options.

twesterhout commented 4 months ago

@bradcray That's an interesting approach. I don't use VSCode, so an extension wouldn't help much... but I think the features that you're describing, such as hover to see the types, are often part of LSPs. So if Chapel's LSP gained support for these features (or perhaps it already has and I just missed it) I'd definitely use them (e.g., I routinely use the "hover" feature in Haskell to see the types because of its extensive type inference, and from time to time in C++ as well when using the "auto everything" approach). Your second idea isn't covered by the LSP protocol though (I think), and being able to inspect the IR (I didn't know Chapel had an IR beyond the AST, cool!) of a given function sounds like a great feature. Especially if casts, remote accesses, task spawns, whether a loop is vectorised, etc. become explicit there, I could imagine dumping the IR to a file and then grepping through it to analyze the code (a similar workflow is possible with the C backend now, but then it's C with all its quirks, and personally I found the C code generated by chpl a bit hard to read though that's likely due to lack of practice with it).

(motivated by feeling nervous about warnings that users don't care about and eventually just start ignoring)

It's not immediately obvious to me whether an IR inspection utility would be more popular among the users than a warning (especially if it's enabled by default :smiling_imp:). To me personally, a warning would yield more value in the short term, but I'd totally understand if you chose a different route.

mppf commented 4 months ago

I think a warning is appropriate here.

(I think the LSP efforts are great and very helpful, and we're working towards including a prototype in the upcoming release. I'm looking forward to hearing your thoughts on it. However, IMO the additional information from the LSP isn't enough to reliably prevent the problem Tom originally ran into here)

Revisiting the example from the records primer, here is a slightly more self-contained reproducer:

proc foo() {
  var red: uint(8) = 1;
  var green: uint(8) = 2;
  var blue: uint(8) = 3;
  return 0.2126*red + 0.7152*green + 0.0722*blue;
}

proc main() {
  var x = foo();
  writeln("foo() = ", x, " : ", x.type:string);
}

In current releases of Chapel (1.27 and newer) this prints:

foo() = 1.8596 : real(32)

But, in older versions of Chapel (1.26 and older) it printed:

foo() = 1.8596 : real(64)

At the same time, programmers coming from other languages might well expect it to result in a real(64) (because that is the type of the floating point constants). As https://github.com/chapel-lang/chapel/issues/24496#issuecomment-1971985249 noted, C and Julia have different behavior. Additionally, my prototype with option (1) showed a relatively small number of tests that trigger the warning. As a result, my expectation is that this warning won't be too annoying & it'll instead help people who run into this behavior in the future.

mppf commented 4 months ago

I've created PR #24529 to add a warning for code like sqrt(2:uint(16)). While there, I added a bunch of other off-by-default warnings that can be used to opt in to further warnings about implicit numeric conversions.

bradcray commented 4 months ago

@twesterhout : Michael has now merged his PR which adds a number of new opt-in numeric conversion warning modes. We'll definitely be curious how you find them, and particularly whether you feel this issue can be closed as a result of them.

bradcray commented 3 months ago

@twesterhout : Not hearing back from you, and being under the impression that we've decided that the OP behavior is OK, I'm going to close this. Please let me know if there's something more that should be done, either to warrant re-opening this or forking an item off into an issue of its own.