# Consistency of eye vs. zeros, ones, rand functions

**URL:** <https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011>\
**Category:** Internals & Design\
**Tags:** question\
**Created:** [February 9, 2017, 10:56pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011 "2017-02-09T22:56:08Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 9, 2017, 10:56pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/1 "2017-02-09T22:56:08Z")

</div>

Hi,  
I’d like to understand better the design of these standard array creation functions, as they seem somewhat inconsistent to me.

Compare these examples:

```julia
a = rand(2);
sz = size(a);
# 1 #
o = ones(a); # 2-element Array{Float64,1} but...
id = eye(a); # ...an error here
# 2 #
o2 = ones(sz...); # 2-element Array{Float64,1} but...
id2 = eye(sz...); # ... 2×2 Array{Float64,2}

```

It is reasonable, that 2x1 identity matrix doesn’t exist, unless that:

```julia
b = rand(2,1);
# 3 #
o3 = eye(b); # 2×1 Array{Float64,2}:
# 4 #
o4 = eye(size(b)...); # 2×1 Array{Float64,2}:

```

So, 3 of 4 molding results of `eye()` are different, while the `ones()`, for instance, produces predictable and consistent results.  
Is it a bug or a feature?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 10, 2017, 7:31am UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/2 "2017-02-10T07:31:54Z")

</div>

When you call `eye(sz...)`, you are calling `eye(::Int)`, which gives you a square matrix. Withl `eye(b)` and `eye(size(b)...)`, you provide the dimensions, and call `eye(::Int,::Int)` (indirectly in the first case, picking the dimensions from `b`).

Since `eye(::Int)` is a much more common use case, this interface is convenient. Note that `ones` / `zeros` can provide arbitrary arrays, while `eye` always gives a matrix. So the two interfaces don’t need to be consistent.

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 12:28pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/4 "2017-02-10T12:28:08Z")

</div>

In terms of matrices, I’d expect both eye(::Int) zeros(::Int) to produce the identity matrix and the all-zeros matrix, but not a matrix and a vector (to create block matrices, for instance).

And still. if eye() creates a 2x1 array, why doesn’t it make a 2-element array with the same contents, as rand() or ones() do?

I’d expect all common matrix generators to behave similarly, e.g. Matlab/Octave, where rand(n) creates an nxn matrix.

Moreover, it would make possible creating higher-order functions (to create the same block matrices as as example) without converting arguments for eye(), rand() etc.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 10, 2017, 12:31pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/5 "2017-02-10T12:31:49Z")

</div>

Letting `zeros(n)` etc. create a matrix would be wildly inconsistent with the rest of Julia. The odd man out here is `eye`, which seems to be special cased because it can only ever be a matrix.

It is bad enough that Matlab does this, but it can sort of be understood because everything is a matrix in Matlab.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 10, 2017, 12:46pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/6 "2017-02-10T12:46:20Z")

</div>

> [@homocomputeris](#):
>
> I’d expect both eye(::Int) zeros(::Int) to produce the identity matrix and the all-zeros matrix

Then your expectations are incorrect. Read the manual. In particular, `zeros` and `ones` produce general arrays (as I said above).

> [@homocomputeris](#):
>
> I’d expect all common matrix generators to behave similarly

But `ones` and `zeros` are not **matrix** generators. They generate **arrays**. The only one that generates matrices is `eye`, that’s why it is different.

> [@homocomputeris](#):
>
> Moreover, it would make possible creating higher-order functions (to create the same block matrices as as example) without converting arguments for eye(), rand() etc.

For matrices, this is already possible, just call all of them with the `(::Int, ::Int)` signature. For other arrays, `eye` does not make sense, or to be more precise, there is no generally used analogue to the identity matrix.

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 12:46pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/7 "2017-02-10T12:46:58Z")

</div>

Could you explain or refer to a source, why is it inconsistent, does any function by default returns a column vector?

> it can only ever be a matrix

That’s also not very clear from the content, not type, point of view. An n-element vector and an nx1 matrix are treated very similarly even in Julia: `B*rand(5,1)-B*rand(5)` works fine, but `eye(rand(5))` throws an error, even not a square matrix.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 10, 2017, 1:01pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/8 "2017-02-10T13:01:37Z")

</div>

It’s inconsistent in the sense that Julia creates general arrays, with `n` dimensions.

The number of shape parameters supplied to the constructor, as in `zeros(n1, n2, n3, ...)` dictates the number of dimensions in the array. So `zeros(4,3,5)` is three-dimensional, `zeros(4,3)` is two-dimensional, and `zeros(4)` is one-dimensional. You are basically arguing that 2 should be the minimum number of dimensions, like in Matlab, which is something I disagree with. If `zeros(4)` should be a matrix, you are essentially removing the concept of a one-dimensional vector from the language.

> [@homocomputeris](#):
>
> An n-element vector and an nx1 matrix are treated very similarly even in Julia: B_rand(5,1)-B_rand(5) works fine

This is just how it is in linear algebra. Matrix-vector products work the same as a matrix-(n-by-1) matrix product. ( **Edit:** except, note that the former produces a matrix while the latter produces a vector.)

I think you might have a case for arguing that `eye` should behave in a slightly different way, but there’s no chance at all `zeros(5)` will ever return a matrix.

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 2:00pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/9 "2017-02-10T14:00:27Z")

</div>

> [@DNF](#):
>
> You are basically arguing that 2 should be the minimum number of dimensions, like in Matlab

Actually, I do not. Sorry, I’ve explained badly. `rand(n)` resulting an nxn matrix is just an example. Similarly, every `generate_something(n)` may produce an n-element vector.

> [@DNF](#):
>
> concept of a one-dimensional vector from the language

What are the advantages of this design, if it behaves very similar to nx1 arrays (or can be substituted by them)?

> [@DNF](#):
>
> I think you might have a case for arguing that eye should behave in a slightly different way, but there’s no chance at all zeros(5) will ever return a matrix.

This is what I mean, in fact. Something like that `eye()` should not throw exceptions and be more similar to the majority in this specific case just to generate e1 n-element vector, which consists of `rand()`, `zeros()` etc.

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 2:20pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/10 "2017-02-10T14:20:47Z")

</div>

> [@Tamas\_Papp](#):
>
> Then your expectations are incorrect.

I _would_ expect that in some imaginary example, I do not expect it. I wanted to emphasize consistency, not the actual syntax.

> [@Tamas\_Papp](#):
>
> But ones and zeros are not matrix generators. They generate arrays.

According to the manual, a matrix is just an aliased array `typealias Matrix{T} Array{T,2}`, so I don’t understand the great difference between them because…

> [@Tamas\_Papp](#):
>
> there is no generally used analogue to the identity matrix.

… `I` can be defined formally for m dimensions as `element(i,j,...l,m) = kronecher_delta(i,j,...,l,m)` and `eye()` can return an nx1 matrix giver an n-elements vector, resulting the same signature as `zeros()` have.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 10, 2017, 3:02pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/11 "2017-02-10T15:02:10Z")

</div>

> [@homocomputeris](#):
>
> What are the advantages of this design, if it behaves very similar to nx1 arrays (or can be substituted by them)?

There are many discussions about this, and I’m not equipped to go into all of it. There are deep reasons having to do with the mathematical differences between vectors and matrices, but there are also practical reasons.

The most obvious reason, to me, is that when writing my code, I always know whether I am dealing with a matrix or a vector, in that they are distinguishable at the type level. If vectors were simply a special case of a matrix, then my code would always have to explicitely check if the matrix has exactly one column, while in Julia this is handled by dispatch.

In Matlab (which I use all the time) it’s a continual headache that vectors are sometimes columns and sometimes rows, and my functions always need boilerplate where I ensure correct and compatible orientation, how to handle matrices etc. _Still_ Matlab frequently frustrates my efforts by throwing row-vectors at me when I let down my guard (`linspace` and `1:n` do this for example, even though Matlab is supposedly column-major!?!!)

I can assure you that in everyday, practical work, it’s a **Yuge** relief to deal with real vectors, instead of the pseudo-vector matrices I’m unfortunately used to.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 10, 2017, 3:08pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/12 "2017-02-10T15:08:14Z")

</div>

> [@homocomputeris](#):
>
> According to the manual, a matrix is just an aliased array typealias Matrix{T} Array{T,2}, so I don’t understand the great difference between them because…

I think he means that they are not _specifically_ matrix generators. It’s like you were complaining that the Ferrari generator is not giving you the correct paint job, and then someone points out it’s not a Ferrari generator, but a generic car generator, so it will not automatically paint the car red.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [February 10, 2017, 3:28pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/13 "2017-02-10T15:28:06Z")

</div>

The core issue here seems to be that `eye(rand(n))` doesn’t work. It could, of course, be made to work. However, there’s an ambiguity about what it should do:

1. Since `eye(m,n)` produces an `m×n` matrix and `eye(n)` produces an `n×n` matrix, one could argue that by analogy `eye(rand(n))` should produce an `n×n` identity matrix.

2. Since vectors and column matrices are largely similarly behaved, one can also argue that `eye(rand(n))` should behave the same as `eye(rand(n,1))` and therefore produce a length `n` vector whose first element is one and the rest zeros.

Since someone might reasonably expect either behavior, it’s better to leave this method undefined and require the user to be explicit about what they want.

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 4:51pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/14 "2017-02-10T16:51:13Z")

</div>

> [@DNF](#):
>
> The most obvious reason, to me, is that when writing my code, I always know whether I am dealing with a matrix or a vector, in that they are distinguishable at the type level.

Could you provide a code snippet to illustrate your idea?

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 4:58pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/15 "2017-02-10T16:58:21Z")

</div>

> [@StefanKarpinski](#):
>
> Since someone might reasonably expect either behavior, it’s better to leave this method undefined and require the user to be explicit about what they want.

It is just a choice to make, as someone has selected, let’s say, “non-Matlab” behavior or that `rand(n,1)` creates a matrix, not a vector. This may also differ from _expected_.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 10, 2017, 5:09pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/16 "2017-02-10T17:09:33Z")

</div>

It seems most consisten, to me at least, that `eye(n)` and `eye(rand(n))` behave one way, and `eye(n,1)` and `eye(rand(n,1))` behave one way.

(Edit: Actually, that came out wrong, and I don’t really see an optimal solution to the above conundrum.)

It’s also sometimes an issue that

```julia
julia> zeros((2,2))
2×2 Array{Float64,2}:
 0.0 0.0
 0.0 0.0

```

while

```julia
julia> eye((2,2))
MethodError: no method matching eye(::Tuple{Int64,Int64})
Closest candidates are:
  eye{T}(::Type{Diagonal{T}}, ::Int64) at linalg/diagonal.jl:242
  eye(::Type{T}, ::Integer) at array.jl:189
  eye(::Type{T}, ::Integer, ::Integer) at array.jl:182

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 10, 2017, 5:50pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/17 "2017-02-10T17:50:19Z")

</div>

`eye` is just awkward. It’s a pretty bad name, and this method signature awkwardness comes directly from it’s Matlabby origins. It’s worth noting that this exact inconsistency also exists in NumPy.

Julia has the special `I` constant that efficiently represents a uniform scaling diagonal matrix. It’s great… except that it cannot be used as an initial value for a matrix that is subsequently modified. It’d be great if we could use `I` in some manner for array initialization, and then deprecate `eye` in favor of that. A few options would be to implement `I[1:5,1:5]` or `A .= I` or maybe even `I(5)` (none of which currently work).

---

<div class="post-metadata">

**Author:** ![homocomputeris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/homocomputeris/32/8933_2.png) [@homocomputeris](https://discourse.julialang.org/u/homocomputeris)\
**Post date:** [February 10, 2017, 7:32pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/18 "2017-02-10T19:32:58Z")

</div>

> [@mbauman](#):
>
> xcept that it cannot be used as an initial value for a matrix that is subsequently modified

Neither it can be a block in a matrix.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 10, 2017, 7:36pm UTC](https://discourse.julialang.org/t/consistency-of-eye-vs-zeros-ones-rand-functions/2011/19 "2017-02-10T19:36:40Z")

</div>

It will be able to on 0.6!

```julia
julia> [2*ones(3) I
        3*ones(3)' 4]
4×4 Array{Float64,2}:
 2.0 1.0 0.0 0.0
 2.0 0.0 1.0 0.0
 2.0 0.0 0.0 1.0
 3.0 3.0 3.0 4.0

```
