>
> It seems you and I are both in agreement that generating an integer as
> output in the case np.select([], []) seems wrong.
>
> Yes.


> The second thing is that while "(empty ndarray) x (empty ndarray) must
> produce (empty ndarray)" looks cute and natural, the human concept of
> selection according to rules - when there aren't any rules or choices -
> isn't as well defined as say, the intellectual concept of merging two empty
> lists.
>
> I'm arguing for having a think here about the meaning and error/warning
> output of this function from first principles rather than simply
> 'definition by existing implementation'. Is this really a case of 0+0, or a
> case of 0/0, or something inbetween? One situation is naturally silent in
> maths, the other requires an error and warning message which comes from the
> semantics of 'dividing'. Here, I think we need at least some warning
> output, which comes from the semantics of selection.
>
If you really set on having this discussion, then the numpy-discussion list
is the right place to do it. But I can tell you that based on my knowledge
and experience, the conclusion will definitely be that the empty ndarray
case should not be treated specially in any way, and should simply return
an empty ndarray.

This is neither 0 + 0 nor 0/0. It' a case of np.array([]) + np.array([]),
which returns np.array([]).

> The third thing, which the highlighted code in the pull request was
> intended to address in a consistent way, was these situations, which I
> think need to be defined (as meaningful or erroneous) and tested.
>
> C - condlist contains 'normal' items to select upon along with an ndarray
> with no items/dimension.
> D - choicelist contains 'normal' items to select upon along with an
> ndarray with no items (in some position).
> E - condlist contains multiple ndarrays that contain no items/dimensions
> (similar to C, but test separately).
> F - choicelist contains multiple ndarrays that contain no items/dimensions
> (similar to D, but test separately).
> G - combinations of the above.
>
You're making this too complicated :-). All the entries in choicelist and
condlist need to broadcast against each other. This is the only rule you
need.

> Case C1 + output (sorry, numpy 1.6.2 is all I have to hand here, and it's
> almost 3 in the morning)
>
>  np.select([np.array([1], dtype=bool),np.array([], dtype=bool)],
> [np.array([1]), np.array([2])]);
> ValueError: non-broadcastable output operand with shape (1) doesn't match
> the broadcast shape (0)
>
>  OK.. that makes sense! You gave weird input, you get an error. Now let's
> simply swap the arguments around... we'll still get the same error/output
> since the underlying problem is still the same?
>
> Nope.
>
> Case C2 + output
>
>  np.select([np.array([], dtype=bool),np.array([1], dtype=bool)],
> [np.array([2]), np.array([1])]);
> array([], dtype=float64)
>
>  Completely different program behaviour when we swap the arguments
> around. (This is an example of why it's a really good idea to have a little
> bit of logic that warns the user when there are peculiar empty arguments to
> a function that really needs arguments or generates an error - it picks up
> on strange implementation artefacts that would otherwise cause silent bugs
> in your code/data).
>
Yep, the C1 case is indicating a bug in your code -- [1] and [] are
broadcastable against each other, so after broadcasting both of these cases
become equivalent to np.select([np.array([], dtype=bool),np.array([],
dtype=bool)], [np.array([]), np.array([])]), and should return an array
with shape (0,).

If, however, you replace [1] with [1, 2], then all of these cases are
errors. It's a special fact about dimensions that have exactly 1 entry
along them that they can broadcast to become any length, including 0.

> Case C3 + output - multiple empty condlists
>
>  np.select([np.array([], dtype=bool),np.array([], dtype=bool)],
> [np.array([1]), np.array([2])]);
> array([], dtype=float64)
>
>  (Looks like an error to me. The datatype & content of the output does
> not correspond to the available options presented as choices in the
> choicelist.)
>
> To make this post shorter, I'll jump to some of the trickier ones to show
> how nasty the problem can get.
>
> Case G1 - 2 empty condlists/choicelists and 1 'meaningful' condlist with
> corresponding 'meaningful' choicelist at list position 1.
>
>  np.select([np.array([], dtype=bool),np.array([1], dtype=bool),
> np.array([], dtype=bool)], [np.array([]), np.array([1]), np.array([])]);
>
>  After reading the documented specification for np.select, what is the
> correct output here, and how well does it correspond to your human
> intuitions about selecting things?
>
Again, according to all the rules that are used everywhere in numpy, this
is just a case of calling select() with a bunch of empty arrays.

Try:
np.array([]) + np.array([1])
np.array([]) + np.array([1, 2])

> So...to sum up - *if* it's meaningful to make selections upon empty
> condlists/choicelists or upon lists that can contain one or more empty
> ndarrays, the behaviour should be well specified, consistent and behaviour *should
> correspond to a natural human understanding about selecting things as well
> as possible* so that user aren't shocked or misled. Datatypes and
> selected values should be consistent and well defined by specification, not
> implementation.
>
Making np.select inconsistent with the entire rest of numpy is not a way to
help users feel less shocked and misled.

These cases look weird when you're just coming up with weird edge-case
input. But the broadcasting rules are simple, consistent, and very useful.

The division_by_self function below is also well defined and returns
> consistent output (1) across inputs. It is also *wrong* in terms of the
> human concepts that go with the idea of dividing a number by itself. In
> mathematics it was decided that it's better to generate an error in the
> case of division by zero rather than make something up. I think the same is
> true of selection by zero.


According to this logic, the sum of zero elements should be an error too,
but that's not how mathematicians think :-)