Implement nelements for various backends

Allows differentiation between `expr.count()` (will eventually ignore `NA`
values) and `expr.nelements()` (never ignores `NA` values).

Also adds an `nrows` property of symbols
Generally reductions on n-dimensional structures with an axis argument that doesn't cover all dimensions leave the other dimensions intact.

```Python
In [1]: import numpy as np

In [2]: x = np.ones((5, 4, 3))

In [3]: x.sum(axis=(0, 2))
Out[3]: array([ 15.,  15.,  15.,  15.])
```

`nelements` is a bit silly in this regard for strict arrays because, like the example above, all results will be identical.  This would be more relevant in the case of ragged arrays.

Ideally

```python
In [4]: data = [[1, 2, 3], [1, 2, 3, 4, 5], [1]]

In [5]: compute(s.nelements(), data)
9

In [6]: compute(s.nelements(axis=0), data)
[3, 5, 1]
```