Repository: dask/dask

Issue:
Cannot specify dask array shape with a numpy array
```python
import numpy as np
import dask.array as da


chunks = (10, 10)
shape = np.asarray((100, 100))

n = np.zeros(shape)
d = da.zeros(shape, chunks=chunks)
```

output
```python
Traceback (most recent call last):

  File "<ipython-input-31-0eb572d2c4ad>", line 1, in <module>
    d = da.zeros(shape, chunks=chunks)

  File "/home/mark/miniconda3/envs/owl/lib/python3.6/site-packages/dask/array/wrap.py", line 36, in wrap_func_shape_as_first_arg
    chunks = normalize_chunks(chunks, shape, dtype=dtype)

  File "/home/mark/miniconda3/envs/owl/lib/python3.6/site-packages/dask/array/core.py", line 1990, in normalize_chunks
    if not (len(shape) == 1 and sum(chunks) == shape[0]):

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
```

You can specify the numpy array shape with a numpy array.

Dask version: 0.18.1
Python: 3.6
Linux 64 bit
Using miniconda




Discussion:
I agree that that is a bug and should be fixed.  Thanks for the excellent issue.  My guess is that there are probably a few places to normalize the shape to a tuple of ints.  Trying this on a few functions should be helpful in identifying most of them.
Incidentally, I realized that I'm not even supposed to create my array this way.
So I don't know if I'm going to care to fix this myself.

For whoever else has this issue: my workaround was to use as I wanted to have flexibility in how 'shape' was defined.

```python
d = da.zeros(list(shape), chunks=chunks)
```

`tuple` might work too.
Also NumPy has the `tolist` method, which is a bit more performant. Though it is unlikely this is ever the bottleneck.

```python
In [1]: import numpy as np

In [2]: shape = np.asarray((100, 100))

In [3]: %timeit list(shape)
952 ns ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit shape.tolist()
152 ns ± 5.13 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
```
Should we close then or would you still like to see this fixed?
@jakirkham I think it became an issue since I wrote some code with the following spirit:

```python
import numpy as np
arr_1 = np.zeros((3, 2))
shape_2 = np.asarray(arr_1.shape)*2
arr_2 = np.zeros(shape=shape_2, dtype=arr_1.dtype)
```
and when I wanted to convert it to dask, I ran into the issue. 

Operating on the shape, as a numpy array is often advantageous.


Resolving patch:
diff --git a/dask/array/core.py b/dask/array/core.py
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -2116,6 +2116,8 @@ def normalize_chunks(chunks, shape=None, limit=None, dtype=None,
         chunks = (chunks,) * len(shape)
     if isinstance(chunks, dict):
         chunks = tuple(chunks.get(i, None) for i in range(len(shape)))
+    if isinstance(chunks, np.ndarray):
+        chunks = chunks.tolist()
     if not chunks and shape and all(s == 0 for s in shape):
         chunks = ((0,),) * len(shape)
 
diff --git a/dask/array/creation.py b/dask/array/creation.py
--- a/dask/array/creation.py
+++ b/dask/array/creation.py
@@ -57,7 +57,8 @@ def empty_like(a, dtype=None, chunks=None):
 
     a = asarray(a)
     return empty(
-        a.shape, dtype=(dtype or a.dtype), chunks=(chunks or a.chunks)
+        a.shape, dtype=(dtype or a.dtype),
+        chunks=(chunks if chunks is not None else a.chunks)
     )
 
 
@@ -92,7 +93,8 @@ def ones_like(a, dtype=None, chunks=None):
 
     a = asarray(a)
     return ones(
-        a.shape, dtype=(dtype or a.dtype), chunks=(chunks or a.chunks)
+        a.shape, dtype=(dtype or a.dtype),
+        chunks=(chunks if chunks is not None else a.chunks)
     )
 
 
@@ -127,7 +129,8 @@ def zeros_like(a, dtype=None, chunks=None):
 
     a = asarray(a)
     return zeros(
-        a.shape, dtype=(dtype or a.dtype), chunks=(chunks or a.chunks)
+        a.shape, dtype=(dtype or a.dtype),
+        chunks=(chunks if chunks is not None else a.chunks)
     )
 
 
@@ -169,7 +172,7 @@ def full_like(a, fill_value, dtype=None, chunks=None):
         a.shape,
         fill_value,
         dtype=(dtype or a.dtype),
-        chunks=(chunks or a.chunks)
+        chunks=(chunks if chunks is not None else a.chunks)
     )
 
 
diff --git a/dask/array/wrap.py b/dask/array/wrap.py
--- a/dask/array/wrap.py
+++ b/dask/array/wrap.py
@@ -24,6 +24,9 @@ def wrap_func_shape_as_first_arg(func, *args, **kwargs):
     else:
         shape = kwargs.pop('shape')
 
+    if isinstance(shape, np.ndarray):
+        shape = shape.tolist()
+
     if not isinstance(shape, (tuple, list)):
         shape = (shape,)
 


Test patch:
diff --git a/dask/array/tests/test_creation.py b/dask/array/tests/test_creation.py
--- a/dask/array/tests/test_creation.py
+++ b/dask/array/tests/test_creation.py
@@ -11,15 +11,17 @@
 
 @pytest.mark.parametrize(
     "funcname", [
-        "empty_like",
-        "ones_like",
-        "zeros_like",
-        "full_like",
+        "empty_like", "empty",
+        "ones_like", "ones",
+        "zeros_like", "zeros",
+        "full_like", "full",
     ]
 )
+@pytest.mark.parametrize("cast_shape", [tuple, list, np.asarray])
+@pytest.mark.parametrize("cast_chunks", [tuple, list, np.asarray])
 @pytest.mark.parametrize(
     "shape, chunks", [
-        ((10, 10), (4, 4)),
+        ((10, 10), (4, 4))
     ]
 )
 @pytest.mark.parametrize(
@@ -27,11 +29,13 @@
         "i4",
     ]
 )
-def test_arr_like(funcname, shape, dtype, chunks):
+def test_arr_like(funcname, shape, cast_shape, dtype, cast_chunks, chunks):
     np_func = getattr(np, funcname)
     da_func = getattr(da, funcname)
+    shape = cast_shape(shape)
+    chunks = cast_chunks(chunks)
 
-    if funcname == "full_like":
+    if "full" in funcname:
         old_np_func = np_func
         old_da_func = da_func
 
@@ -40,15 +44,19 @@ def test_arr_like(funcname, shape, dtype, chunks):
 
     dtype = np.dtype(dtype)
 
-    a = np.random.randint(0, 10, shape).astype(dtype)
+    if "like" in funcname:
+        a = np.random.randint(0, 10, shape).astype(dtype)
 
-    np_r = np_func(a)
-    da_r = da_func(a, chunks=chunks)
+        np_r = np_func(a)
+        da_r = da_func(a, chunks=chunks)
+    else:
+        np_r = np_func(shape, dtype=dtype)
+        da_r = da_func(shape, dtype=dtype, chunks=chunks)
 
     assert np_r.shape == da_r.shape
     assert np_r.dtype == da_r.dtype
 
-    if funcname != "empty_like":
+    if "empty" not in funcname:
         assert (np_r == np.asarray(da_r)).all()