Fixing Broadcast

Reimplement `Broadcast` operation for fusing scalar expressions over collections.

## Broadcast docstring

Given elementwise operations on collections, e.g.
```Python
>>> a = Symbol('a', '100 * int')
>>> t = Symbol('t', '100 * {x: int, y: int}')

>>> expr = sin(a) + t.y**2
```
It may be best to represent this as a scalar expression mapped over a
collection
```Python
>>> sa = Symbol('a', 'int')
>>> st = Symbol('t', '{x: int, y: int}')

>>> sexpr = sin(sa) + st.y**2

>>> expr = Broadcast((a, t), (sa, st), sexpr)
```
This provides opportunities for optimized computation.

In practice, expressions are often collected into Broadcast expressions
automatically.  This class is mainly intented for internal use.

## Optimization issues

Generally we don't construct `Broadcast`s by hand.  Instead, there are a few scattered functions to collect up operations of various types automatically using the somewhat new-and-experimental `optimize` framework.  There are a few of these due to slight differences in how the backends want operations bundled up.  Probably this should be cleaned up a bit.

## TODO

- [ ] Optimize should work on subtrees
    currently we only call `expr = optimize(expr, *leaves)` at the onset of `compute`.  In cases where we have multiple leaves (as in a join or binop) then this often fails, because we usually only define `optimize` for a single data input type.  Really we should call this down the tree to optimize subtrees with a single leaf.
- [ ] Nested Python data structures
- [ ] Intelligent handling (or at least erring) in Python cases where we might consume an iterator twice
- [ ] numexpr support in numpy
Fixed hash issue with call to abs

On Wed, Oct 29, 2014 at 1:13 PM, Phillip Cloud <notifications@github.com>
wrote:

> In blaze/compute/mongo.py:
>
> > @@ -127,7 +136,11 @@ def compute_up(t, q, **kwargs):
> >
> >  @dispatch(Broadcast, MongoQuery)
> >  def compute_up(t, q, **kwargs):
> > -    return q.append({'$project': {str(t._expr): compute_sub(t._expr)}})
> > +    s = t._scalars[0]
> > +    d = {s[c]: Symbol(c, s[c].dshape.measure) for c in s.fields}
> > +    expr = t._scalar_expr._subs(d)
> > +    name = expr._name or 'expr_%d' % hash(expr)
>
> is this meant to be a valid identifier? if expr hashes to negative value
> you won't have one
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/ContinuumIO/blaze/pull/777/files#r19568744>.
>