Nicer syntax collect(linspace(0,1,n))?

1,411 views
Skip to first unread message

feza

unread,
Sep 29, 2015, 6:44:43 PM9/29/15
to julia-users
In matlab  x = linspace(0,1,n)  creates a vector of floats of length n. In julia it seems like the only way to do this is to use x = collect( linspace(0,1,n) ) . Is there a nicer syntax? I do mainly numeric computing and I find this quite common in my code.

Thanks.

Luke Stagner

unread,
Sep 29, 2015, 8:31:13 PM9/29/15
to julia-users
I'm not sure what version of Julia you are using but in Julia 0.3.9 x = linspace(0,1,N) does return a linearly spaced N-element array of floats from 0-1

Chris

unread,
Sep 29, 2015, 8:43:28 PM9/29/15
to julia-users
In 0.4 the linspace function returns a range object, and you need to use collect() to expand it. I'm also interested in nicer syntax.

Patrick Kofod Mogensen

unread,
Sep 29, 2015, 8:48:08 PM9/29/15
to julia-users
Is it because you use it many times? just define a clinspace that collects the linspace.

Luke Stagner

unread,
Sep 29, 2015, 8:50:47 PM9/29/15
to julia-users
Thats interesting. Does logspace also return a range?

Patrick Kofod Mogensen

unread,
Sep 29, 2015, 8:55:25 PM9/29/15
to julia-users
No:

julia> logspace(0,3,5)
5-element Array{Float64,1}:
    1.0   
    5.62341
   31.6228
  177.828 
 1000.0  

Stefan Karpinski

unread,
Sep 29, 2015, 8:59:52 PM9/29/15
to julia...@googlegroups.com
I'm curious why you need a vector rather than an object. Do you mutate it after creating it? Having linspace return an object instead of a vector was a bit of a unclear judgement call so getting feedback would be good.

Luke Stagner

unread,
Sep 29, 2015, 9:12:11 PM9/29/15
to julia-users
Personally I don't like the behaviour. (Perhaps I am just too used to numpy/matlab convention). Also we already had linrange (although curiously not logrange) if we wanted to use a range.

Chris

unread,
Sep 29, 2015, 9:13:37 PM9/29/15
to julia...@googlegroups.com

For me, I think I just expect a vector from experience, and I could probably just change the way I work with a little effort.

One exception (I think) is that I often do numerical integration over a range of values, and I need the results at every value. I'm not sure if there's a way to do that with range objects only.

Luke Stagner

unread,
Sep 29, 2015, 9:37:44 PM9/29/15
to julia-users
A range should act (for the most part) exactly like an array. For example indexing into a range is identical (syntax-wise) to indexing an array. What I am concerned about is performance. For instance if I had a range that has a large amount of elements would indexing into it be slower then indexing into an array? Wouldn't the range have to compute the value every single time instead of just doing a memory lookup? Or is the calculation of elements trivial and the memory savings make up for it?

Performance questions aside, having linspace return a range instead of an array just feels like a change for changes sake. I don't see a good reason for displacing the behaviour of linspace for a behaviour that already realized in linrange.

-Luke
Message has been deleted

feza

unread,
Sep 29, 2015, 10:10:55 PM9/29/15
to julia-users
Here's the code I was using where I needed to use collect (I've been playing around with Julia, so any suggestions on this code for perf is welcome ;) ) . In general linspace (or the : notation)  is also used commonly to lay  a grid in space for solving a PDE for some other use cases. 

function gp(n)
n = convert(Int,n)
t0 = 0
tf = 5
t = collect( linspace(t0, tf, n+1) )
sigma = exp( -(t - t[1]) )

c = [sigma; sigma[(end-1):-1:2]]
lambda = fft(c)
eta = sqrt(lambda./(2*n))

Z = randn(2*n) + im*randn(2*n)
x = real( fft( Z.*eta ) )
return (x, t)
end

Sheehan Olver

unread,
Sep 29, 2015, 10:28:12 PM9/29/15
to julia-users
fez, I'm pretty sure the code works fine without the collect: when exp is called on linspace it converts it to a vector.  Though the returned t will be linspace object.

ele...@gmail.com

unread,
Sep 29, 2015, 10:56:12 PM9/29/15
to julia-users


On Wednesday, September 30, 2015 at 11:37:44 AM UTC+10, Luke Stagner wrote:
A range should act (for the most part) exactly like an array. For example indexing into a range is identical (syntax-wise) to indexing an array. What I am concerned about is performance. For instance if I had a range that has a large amount of elements would indexing into it be slower then indexing into an array? Wouldn't the range have to compute the value every single time instead of just doing a memory lookup? Or is the calculation of elements trivial and the memory savings make up for it?

If the memory lookup isn't cached it is likely to be much slower than the calculation which is in core.  Of course if you use the same value repeatedly the optimiser might avoid re-calculating it, and it might avoid re-reading the memory.  Only benchmarks of your particular problem can tell.

And of course a range can be bigger than memory.
Message has been deleted

feza

unread,
Sep 29, 2015, 11:40:40 PM9/29/15
to julia-users
Strange it *was* giving me an error saying deprecated and that I should use collect, but now it's fine.

Michele Zaffalon

unread,
Sep 30, 2015, 2:56:20 AM9/30/15
to julia...@googlegroups.com
Just curious: linspace returns a Range object, but logspace returns a vector because there is no much use case for a LogRange object?

@feza: I have also seen the deprecation warning going away after a couple of calls, but I am not sure why. If you restart Julia, the deprecations reappear.

Milan Bouchet-Valat

unread,
Sep 30, 2015, 3:50:16 AM9/30/15
to julia...@googlegroups.com
Le mercredi 30 septembre 2015 à 08:55 +0200, Michele Zaffalon a écrit :
> Just curious: linspace returns a Range object, but logspace returns a
> vector because there is no much use case for a LogRange object?
>
> @feza: I have also seen the deprecation warning going away after a
> couple of calls, but I am not sure why. If you restart Julia, the
> deprecations reappear.
Deprecation warnings are only printed once for each call place. The
idea is that once you're aware of it, there's no point in nagging you.

Anyway, that warning is most probably not related to linspace at all,
but rather to the array concatenation syntax resulting in an effect
equivalent to collect(). If you show us a piece of code that prints the
warning, we can give you more details.


Regards

Michele Zaffalon

unread,
Sep 30, 2015, 5:18:16 AM9/30/15
to julia...@googlegroups.com
On Wed, Sep 30, 2015 at 9:50 AM, Milan Bouchet-Valat <nali...@club.fr> wrote:
Le mercredi 30 septembre 2015 à 08:55 +0200, Michele Zaffalon a écrit :
> Just curious: linspace returns a Range object, but logspace returns a
> vector because there is no much use case for a LogRange object?
>
> @feza: I have also seen the deprecation warning going away after a
> couple of calls, but I am not sure why. If you restart Julia, the
> deprecations reappear.
Deprecation warnings are only printed once for each call place. The
idea is that once you're aware of it, there's no point in nagging you.

Anyway, that warning is most probably not related to linspace at all,
but rather to the array concatenation syntax resulting in an effect
equivalent to collect(). If you show us a piece of code that prints the
warning, we can give you more details.


Regards

Sorry, you are right, I was referring to the concatenation.
It prints it exaclty twice if I type it in the REPL, it always prints it if I define it within a function e.g. a() = [1:3].

C:\Users\michele.zaffalon>julia
               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: http://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.4.0-rc2 (2015-09-18 17:51 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-w64-mingw32

julia> [1:3]
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in vect at abstractarray.jl:32
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> [1:3]
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in vect at abstractarray.jl:32
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> [1:3]
3-element Array{Int64,1}:
 1
 2
 3

julia> a() = [1:3]
a (generic function with 1 method)

julia> a()
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in a at none:1
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> a()
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in a at none:1
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> a()
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in a at none:1
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

Michele Zaffalon

unread,
Sep 30, 2015, 5:21:36 AM9/30/15
to julia...@googlegroups.com
I just realize that the thread is about 0.3.11 and I am showing output for 0.4.0-rc2. Sorry for the noise.

Christoph Ortner

unread,
Sep 30, 2015, 11:53:57 AM9/30/15
to julia-users
I also strongly dislike the `linspace` change; I like the idea though of having `linspace` and `linrange`, where the former should give the array.
Christoph

J Luis

unread,
Sep 30, 2015, 1:19:22 PM9/30/15
to julia-users
I want to add my voice to the dislikers. Those are the type of surprises that are not welcome mainly for matlab users.

Alex Ames

unread,
Sep 30, 2015, 1:31:55 PM9/30/15
to julia-users
Another downvote on linspace returning a range object. It seems odd for linspace and logspace to return different types, and linrange provides the low-memory option where needed. Numpy's `linspace` also returns an array object.
 I ran into errors when trying to plot a function over a linspace of x values, since plotting libs currently expect vectors as arguments, not range objects. Easily fixed if you know Julia well, but Matlab/Python converts may be stymied.

Milan Bouchet-Valat

unread,
Sep 30, 2015, 2:17:45 PM9/30/15
to julia...@googlegroups.com
Le mercredi 30 septembre 2015 à 10:31 -0700, Alex Ames a écrit :
> Another downvote on linspace returning a range object. It seems odd
> for linspace and logspace to return different types, and linrange
> provides the low-memory option where needed. Numpy's `linspace` also
> returns an array object.
> I ran into errors when trying to plot a function over a linspace of
> x values, since plotting libs currently expect vectors as arguments,
> not range objects. Easily fixed if you know Julia well, but
> Matlab/Python converts may be stymied.
This sounds more like an issue with the plotting libraries. In most
cases, you shouldn't care about the actual type of a read-only
AbstractArray. If they only support the Array type, people will run
into the same issue when using integer ranges à la 1:10 anyway.

Do you have other examples in which returning a range object is an
issue? So far, that's the only one I've read (except for the confusion
about deprecation warnings).

Regards

Mauro

unread,
Sep 30, 2015, 2:42:58 PM9/30/15
to julia...@googlegroups.com
I don't understand this obsession with wanting to store a bunch of
numbers in memory which trivially compress. Even more so as most
numerical computations are memory bound, so storing more stuff is bad.
All the interface functions work with a range (or if not a bug report
should be filed), apart from write. However, writing to a
range-like-thing should be rare, most often probably a bug, and thus
should be a conscious decision; so it is actually good to have to
`collect` first.

I suspect the reason the logspace returns a vector is because no one had
time to implement it yet.

Christoph Ortner

unread,
Sep 30, 2015, 2:51:46 PM9/30/15
to julia-users
I, on the other hand, don't understand the obsession with abstraction.

Also, by your argument the following should all be special types rather than box-standard arrays. 

julia> typeof(ones(10))
Array{Float64,1}

julia> typeof(zeros(10))
Array{Float64,1}

julia> typeof(eye(10))
Array{Float64,2}




Christoph Ortner

unread,
Sep 30, 2015, 2:53:10 PM9/30/15
to julia-users
I wasn't even aware that linspace in Python also gives an array. What about R? I think some consistency with existing terminology is useful, at the very least for early adopter.

Steven G. Johnson

unread,
Sep 30, 2015, 2:56:23 PM9/30/15
to julia-users


On Wednesday, September 30, 2015 at 1:31:55 PM UTC-4, Alex Ames wrote:\
 I ran into errors when trying to plot a function over a linspace of x values, since plotting libs currently expect vectors as arguments, not range objects. Easily fixed if you know Julia well, but Matlab/Python converts may be stymied.

PyPlot works fine with linspace arguments.

In Julia, a Range is a subtype of AbstractVector, and any plotting program should normally work for any AbstractVector type, not just Array.  If not, that is a bug in the plotting program. 

Steven G. Johnson

unread,
Sep 30, 2015, 3:01:55 PM9/30/15
to julia-users


On Wednesday, September 30, 2015 at 2:51:46 PM UTC-4, Christoph Ortner wrote:
I, on the other hand, don't understand the obsession with abstraction.

Also, by your argument the following should all be special types rather than box-standard arrays. 

julia> typeof(ones(10))
Array{Float64,1}

julia> typeof(zeros(10))
Array{Float64,1}

Arrays of ones and (especially) zeros are commonly used as a starting point for something that is written to, so it would be much less useful for these to return read-only objects.

More generally, returning an Array is much easier to implement (less code), so Base is only going to return special objects in cases that are extremely widely used to allocate what would otherwise be very large objects, like linspace. 

julia> typeof(eye(10))
Array{Float64,2}

Actually, Julia does have a special "I" object and corresponding type for operations with the identity matrix.  e.g. A + 3I is more efficient than A + 3*eye(A), because in A+3I only the diagonals have to be added.

Art Kuo

unread,
Sep 30, 2015, 3:02:39 PM9/30/15
to julia-users
Since range and array are more or less interchangeable computationally (but not memory-wise), I suspect the main issue is how a range object should be reported in the REPL. Julia REPL already tries to be smart about reporting an array, either listing out all the elements or showing the beginning and end with ellipsis in between. Perhaps it would be helpful to do something like this:

julia> linspace(0,10,1000)
1001-element Range{Float64,1}:
0.0
0.1
...
10.0  

Or some such; it's probably wrong to express Range as a container like Array. But idea is that in the REPL, when someone queries a range or array, they probably want to see what's in it, because they want to verify whether the generator does what they intended. So it would help to inform the user that the object is indeed a range, the type it contains, and a summary of the actual values therein. 


On Wednesday, September 30, 2015 at 2:51:46 PM UTC-4, Christoph Ortner wrote:

Mauro

unread,
Sep 30, 2015, 3:02:48 PM9/30/15
to julia...@googlegroups.com
> I, on the other hand, don't understand the obsession with abstraction.

I guess reasons to use a high-level language differ, which is good. As
long as we don't get too obsessive ;-)

> Also, by your argument the following should all be special types rather
> than box-standard arrays.
>
> julia> typeof(ones(10))
> Array{Float64,1}
>
> julia> typeof(zeros(10))
> Array{Float64,1}

I think these two are used to initialise an array, otherwise you'd just
use 0 and 1.

> julia> typeof(eye(10))
> Array{Float64,2}

Yes, that is something to consider for change, maybe this should be the
standard:

Diagonal(eye(10))

Matt Bauman

unread,
Sep 30, 2015, 3:27:02 PM9/30/15
to julia-users
There can be reasons where a special read-only `Ones` array type is beneficial: http://stackoverflow.com/a/30968709/176071.  It's just five lines of code, and Julia/LLVM is able to optimize it such that multiplication is totally elided.  It's pretty cool.  But as others said, these functions are fairly well entrenched in creating mutable arrays.  The output from linspace, however, isn't typically mutated.

Back to linspace, I'm still curious to hear more reasons for the strong dislike.  Is it because of how it behaves?  Or how it performs?  Or how it's displayed (which is also valid)?

feza

unread,
Sep 30, 2015, 3:45:35 PM9/30/15
to julia-users
FYI  this discussion is in relation to Julia 0.4.  Initially I had some deprecation warnings but they have mostly gone away. I have no real objection,  perhaps it's just a little weird that the repl  returns
julia> x
linspace(0.0,10.0,50)

as opposed to printing it out like a full array. Perhaps that would be a nice addition.

Luke Stagner

unread,
Sep 30, 2015, 3:58:31 PM9/30/15
to julia-users
My main objection is that changing the behaviour of linspace is superfluous considering linrange already existed. If the goal was to encourage users to use a range instead of an array that should of been done through documentation through something like a best practices section (e.g. Use linrange instead of linspace). 

Christoph Ortner

unread,
Sep 30, 2015, 4:01:17 PM9/30/15
to julia-users


On Wednesday, 30 September 2015 20:27:02 UTC+1, Matt Bauman wrote:
There can be reasons where a special read-only `Ones` array type is beneficial: http://stackoverflow.com/a/30968709/176071.  It's just five lines of code, and Julia/LLVM is able to optimize it such that multiplication is totally elided.  It's pretty cool.  But as others said, these functions are fairly well entrenched in creating mutable arrays.  The output from linspace, however, isn't typically mutated.

Back to linspace, I'm still curious to hear more reasons for the strong dislike.  Is it because of how it behaves?  Or how it performs?  Or how it's displayed (which is also valid)?

I actually have no problem with an abstract Ones type or with the I that Steven mentioned. 

I simply dislike is that linspace does not behave as expected, and I expect that this is the main reason for other as well. To give an extreme analogy, we don't go around and start defining A * B = A + B either, and linspace and similar names are just so ingrained in the Matlab (and apparently also Python) community, that it trips us up when they suddenly behave differently.

Finally, I don't buy the argument that linspace should be abstracted because of memory. It always creates one-dimensional grids, and those aren't the issue. There is a much stronger argument to create an abstraction for meshgrid and I even disliked that that one was dropped.

Christoph Ortner

unread,
Sep 30, 2015, 4:01:46 PM9/30/15
to julia-users


On Wednesday, 30 September 2015 20:58:31 UTC+1, Luke Stagner wrote:
My main objection is that changing the behaviour of linspace is superfluous considering linrange already existed. If the goal was to encourage users to use a range instead of an array that should of been done through documentation through something like a best practices section (e.g. Use linrange instead of linspace).  

Thank you. I fully agree.
 

Steven G. Johnson

unread,
Sep 30, 2015, 4:42:33 PM9/30/15
to julia-users


On Wednesday, September 30, 2015 at 4:01:17 PM UTC-4, Christoph Ortner wrote:
I simply dislike is that linspace does not behave as expected, and I expect that this is the main reason for other as well. To give an extreme analogy, we don't go around and start defining A * B = A + B either, and linspace and similar names are just so ingrained in the Matlab (and apparently also Python) community, that it trips us up when they suddenly behave differently.

This is a bad analogy.  linspace still returns an AbstractVector with the same elements.   So, it's basically doing the same thing as before, and is just implemented differently.

The question is, why does this implementation detail of linspace matter to you?  It still behaves the same way in nearly every context.  The cases where it behaves differently are probably mostly bugs (overly restrictive types of function parameters) that were waiting to be caught.
 

Finally, I don't buy the argument that linspace should be abstracted because of memory. It always creates one-dimensional grids, and those aren't the issue. There is a much stronger argument to create an abstraction for meshgrid and I even disliked that that one was dropped.

We don't need an abstraction for meshgrid, since in pretty much all applications of meshgrid you can use broadcasting operations instead (far more efficiently).

I used to want meshgrid too, but it was only because I wasn't used to broadcasting operations. Since then, I have never found a case in which meshgrid would have been easier than the broadcasting operations.

Christoph Ortner

unread,
Oct 1, 2015, 12:45:00 AM10/1/15
to julia-users


On Wednesday, 30 September 2015 21:42:33 UTC+1, Steven G. Johnson wrote:


On Wednesday, September 30, 2015 at 4:01:17 PM UTC-4, Christoph Ortner wrote:
I simply dislike is that linspace does not behave as expected, and I expect that this is the main reason for other as well. To give an extreme analogy, we don't go around and start defining A * B = A + B either, and linspace and similar names are just so ingrained in the Matlab (and apparently also Python) community, that it trips us up when they suddenly behave differently.

This is a bad analogy.  linspace still returns an AbstractVector with the same elements.   So, it's basically doing the same thing as before, and is just implemented differently.

My point was about "changing the expected behaviour", and I said this was an extreme analogy.
 
The question is, why does this implementation detail of linspace matter to you?  It still behaves the same way in nearly every context.

as you say, "nearly".
 
 The cases where it behaves differently are probably mostly bugs (overly restrictive types of function parameters) that were waiting to be caught.

julia> x = linspace(0, 1, 1_000_000);
julia> y = collect(x);
julia> @time exp(x);
  0.021086 seconds (6 allocations: 7.630 MB)
julia> @time exp(y);
  0.012749 seconds (6 allocations: 7.630 MB)
julia> @time AppleAccelerate.exp!(y,y);
  0.001282 seconds (4 allocations: 160 bytes)
julia> @time AppleAccelerate.exp!(x,x);
ERROR: MethodError: `exp!` has no method matching exp!(::LinSpace{Float64}, ::LinSpace{Float64})

(a) the speed improvement is probably hidden in the call to collect, but if I don't know about it and call several functions on x, then I will feel it.
(b) The error tells what is going wrong, which is good, so now I can go and fix it. But it is an extra 5-10 minutes taking me out of my flow-state, which in practise will cost me more like 1h or so.

You could now argue that when I try to optimise like that then I should know what I am doing. But I would equally argue that when you care whether linspace is a vector or a "range", then I should know whether to call linspace or linrange. 
 
 Finally, I don't buy the argument that linspace should be abstracted because of memory. It always creates one-dimensional grids, and those aren't the issue. There is a much stronger argument to create an abstraction for meshgrid and I even disliked that that one was dropped.

We don't need an abstraction for meshgrid, since in pretty much all applications of meshgrid you can use broadcasting operations instead (far more efficiently).

I used to want meshgrid too, but it was only because I wasn't used to broadcasting operations. Since then, I have never found a case in which meshgrid would have been easier than the broadcasting operations.

same point really. Why not provide mesh-grid and make it behave as expected,  and add a comment in the documentation (maybe even in the doc-string of mesh grid) that for performance one should use broadcasting.

The whole discussion reminds a bit about issue #10154, https://github.com/JuliaLang/julia/issues/10154, whether floating-point indexing should be implemented. By now I am used to it, and I will get used to linspace behaving as it does. But with every little change like that, the entry barrier for Matlab / R / Python users becomes higher and the take-up of the language by non-experts will decrease. The reason I started with Julia was that it behaved as I expected. I am now sticking with it because I like the type system, the Python interface (and the speed). But if I tried it right now, coming from Matlab, I would have struggled more than I did in the 0.2 version.

Christoph

Sheehan Olver

unread,
Oct 1, 2015, 12:53:42 AM10/1/15
to julia...@googlegroups.com
The timings seem to be a sign that special functions over ranges are not yet optimized, see variants below using comprehensions that do much better.  Note also that collect uses 2x the memory with only a 30% speedup (or 10% slow down, if you also count the time to collect).  



julia> function expfor(n)
       x= linspace(0, 1, n)
       [exp(y) for y in x]
       end
julia> function expcollect(n)
       x= collect(linspace(0, 1, n))
       exp(x)
       end
julia> function explin(n)
       x= linspace(0, 1, n)
       exp(x)
       end

julia> @time for k=1:10 expfor(1_000_000);end
  0.180067 seconds (20 allocations: 76.295 MB, 4.09% gc time)

julia> @time for k=1:10 expcollect(1_000_000);end
  0.209594 seconds (50 allocations: 152.590 MB, 6.43% gc time)

julia> @time for k=1:10 explin(1_000_000);end
  0.254747 seconds (20 allocations: 76.295 MB, 2.85% gc time)

julia> x=collect(linspace(0, 1, 1_000_000));
julia> @time for k=1:10 exp(x);end
  0.136381 seconds (20 allocations: 76.295 MB, 4.74% gc time)

Tim Holy

unread,
Oct 1, 2015, 3:49:13 AM10/1/15
to julia...@googlegroups.com
Ranges check bounds when you index them with x[i], but not when you use `for y
in x`. Someone could submit a PR for the appropriate change in base/ops.jl.

--Tim

Sheehan Olver

unread,
Oct 1, 2015, 8:37:28 AM10/1/15
to julia...@googlegroups.com

I think an argument for linspace returning an Array is that it makes teaching new programmers Julia a lot easier.

If it returns an Array, its sufficient to teach students the Array type. But if it returns a Range, one has to teach an extra data type before the students can use it. Teaching [1:5;] is not as bad as one can just teach that as the syntax for creating an array of [1,2,3,4,5]. (Teaching the syntax [linspace(1,5,1);] is too over the top I think.)


+ linrange exists for experts

Steven G. Johnson

unread,
Oct 1, 2015, 9:03:24 AM10/1/15
to julia-users


On Thursday, October 1, 2015 at 8:37:28 AM UTC-4, Sheehan Olver wrote:

        I think an argument for linspace returning an Array is that it makes teaching new programmers Julia a lot easier.

 If it returns an Array, its sufficient to teach students the Array type.  But if it returns a Range, one has to teach an extra data type before the students can use it. 

Why?   Why should students care about the type at all in order to use the result?  At the beginning level, you normally wouldn't declare argument types to functions at all, e.g. f(x) = ....   At a more advanced level, where you are using multiple dispatch, they should really learn to use abstract types like AbstractVector for declaring arguments, so that their functions are type-generic.   Dispatching on Array (rather than AbstractArray) is usually a mistake, and it's better not to learn bad habits early.

Steven G. Johnson

unread,
Oct 1, 2015, 9:04:01 AM10/1/15
to julia-users


On Thursday, October 1, 2015 at 3:49:13 AM UTC-4, Tim Holy wrote:
Ranges check bounds when you index them with x[i], but not when you use `for y
in x`. Someone could submit a PR for the appropriate change in base/ops.jl.

See also https://github.com/JuliaLang/julia/issues/13401 for discussion of performance problems with LinSpace ranges. 

Sheehan Olver

unread,
Oct 1, 2015, 9:14:40 AM10/1/15
to julia...@googlegroups.com
 saying "linspace returns a vector" is a lot easier than explaining "linspace returns a special data type that sometimes acts like a vector, except for when you try to write to it, etc." since linspace is a basic function in numerical analysis, it would come up way before trying to introduce the notion of abstract types.

Sent from my iPad

Tamas Papp

unread,
Oct 1, 2015, 9:28:56 AM10/1/15
to julia...@googlegroups.com
On Thu, Oct 01 2015, Sheehan Olver <dlfiv...@gmail.com> wrote:

> I think an argument for linspace returning an Array is that it makes teaching new programmers Julia a lot easier.
>
> If it returns an Array, its sufficient to teach students the Array type. But if it returns a Range, one has to teach an extra data type before the students can use it. Teaching [1:5;] is not as bad as one can just teach that as the syntax for creating an array of [1,2,3,4,5]. (Teaching the syntax [linspace(1,5,1);] is too over the top I think.)

Certainly it is a new concept to learn if one wants to understand the
implementation, but it also demonstrates the elegance of Julia: you can
have a type that behaves like an array in many respects, but at the same
time does not store all that information explicitly. This also has
pedagogical value.

Trying to transform Julia in such a way that it has "no surprises
compared to X", where X is Matlab, R, C, Python, etc, has two possible
pitfalls:

1. there will never be an agreement about what the right X is (see the
infamous string concatenation operator issue),

2. many great features would be lost, making Julia nothing but an
incremental improvement over X.

As a new Julia user, I found linspace and how it integrates into the
whole Julia iteration framework very elegant. Sure, it was different
than what I was used to in other languages, but I value elegance over
familiarity -- after all, I am learning a new language.

Best,

Tamas

Sheehan Olver

unread,
Oct 1, 2015, 9:41:43 AM10/1/15
to julia...@googlegroups.com
I agree and mostly fall in the camp of keeping the new behaviour. in my experience trying to attract MATLAB users is a waste of time: the faster code is in MATLAB the slower it is in Julia, which makes for an awful first experience. It's also not clear why at this early stage Julia would want to attract "non-expert" users, as the syntax is still changing each revos.

But linspace is a bit awkward as it sometimes plays a role like "ones" or "zeros". Thinking about trying to teach new programmers Julia in a Math Comp class makes me lean towards the simplicity of it just returning a vector.




Sent from my iPad

David P. Sanders

unread,
Oct 1, 2015, 10:32:08 AM10/1/15
to julia-users


El martes, 29 de septiembre de 2015, 17:44:43 (UTC-5), feza escribió:
In matlab  x = linspace(0,1,n)  creates a vector of floats of length n. In julia it seems like the only way to do this is to use x = collect( linspace(0,1,n) ) . Is there a nicer syntax? I do mainly numeric computing and I find this quite common in my code.

Nobody seems to have mentioned the nicer (at least shorter) syntax:

x = [linspace(0, 1, n) ;]

Note that the ; at the end (which is the concatenation operator) will be required starting with the next version of Julia.

Nonetheless, I find  collect(linspace(0, 1, n)) arguably clearer.

Nils Gudat

unread,
Oct 1, 2015, 10:45:59 AM10/1/15
to julia-users
Given that I had been using convert(Array{Float64,1}, linspace(0,1,n)) so far, I think the collect() syntax is great :)

Jan Strube

unread,
Oct 2, 2015, 1:42:53 PM10/2/15
to julia-users
Just to add my 2 cents:
I posted a question about linspace and collect not too long ago.
Collect wasn't obvious to me at first, and I tried something like linspace (0, 1, 10)[:] to get the array first.
I only needed it for PyPlot. As long as PyPlot works with whatever linspace returns, I'm happy.

Art Kuo

unread,
Oct 7, 2015, 8:05:19 PM10/7/15
to julia-users
I've coded up a simple replacement to the show() function for ranges. The idea is to give the user information more likely to be what they are wondering. Here are some examples of its output:

julia> 0:4

5-element UnitRange{Int64}:

0,1,2,3,4


julia> 0:10

11-element UnitRange{Int64}:

0,1,2,…,9,10


julia> 0:2:20

11-element StepRange{Int64,Int64}:

0,2,4,…,18,20


julia> linspace(0,4,7)

7-element LinSpace{Float64}:

0.0,0.666667,1.33333,…,3.33333,4.0


Any thoughts on this arrangement? The output differs from collect() in that I've arranged elements in a compact row. Also I've assumed that it's sufficient to print out only the first three elements, and the last two, because the user should be able to figure it out from there. A possible point of confusion is "7-element" which isn't actually true of the Range object. Would it be better to output "7-length" or something else?

Steven G. Johnson

unread,
Oct 7, 2015, 10:53:00 PM10/7/15
to julia-users


On Wednesday, October 7, 2015 at 8:05:19 PM UTC-4, Art Kuo wrote:
I've coded up a simple replacement to the show() function for ranges. The idea is to give the user information more likely to be what they are wondering. Here are some examples of its output:

It looks great to me; please consider submitting a pull request. 

Any thoughts on this arrangement? The output differs from collect() in that I've arranged elements in a compact row. Also I've assumed that it's sufficient to print out only the first three elements, and the last two, because the user should be able to figure it out from there. A possible point of confusion is "7-element" which isn't actually true of the Range object. Would it be better to output "7-length" or something else?

"7-element" is nice because it mirrors the output for Array objects.  I don't see the problem.
 

Steven G. Johnson

unread,
Oct 7, 2015, 10:55:05 PM10/7/15
to julia-users
Note, however, that this "display" output should probably be a method of writemime(io::IO, ::MIME"text/plain", x).  The show(io, x) for ranges should continue to be the compact output.

Chris

unread,
Oct 8, 2015, 12:55:28 PM10/8/15
to julia-users
+1, I like the new display a lot.

le...@neilson-levin.org

unread,
Oct 8, 2015, 3:47:02 PM10/8/15
to julia-users
I know it may feel to the insiders/developers that the requestors are being a bit dogmatic with expectations from other languages.

2 cautions:
1.  Insiders need to be careful not to be defensive:  converts are here because they are fans and evangelists (potentially) in their community. Gotchas hurt that evangelism subtly.  And insiders need to also be careful that they don't only listen to POV that is entirely julian (even though there is much good in julian).  "Noobs" will never seem as cogent or knowledgeable in these discussion as insiders (no disrespect meant to any poster!).  But, we were all once noobs (I am sort of perpetually there...).

2. Now is the time to really think it through.  As the language matures and gains more users it gets harder and harder to make such changes. So as entrenched as positions may tend to get--be diplomatic and understanding.  This is just one decision, but a whole set of these decisions make an impact on the language. A priority on clarity and ease of programming is really important--more so than a too early focus on optimization.  Whichever approach is adopted, some sort of optimization is later possible (to a point--needing memory to hold an instantiated vector is a harder thing to optimize).

Julians are really great for be willing to discuss and consider options so openly.  

Art Kuo

unread,
Oct 8, 2015, 10:56:31 PM10/8/15
to julia-users
Oh, clearly I did not understand show(). I've ported the changes to writemime instead, and as a bonus figured out how to automatically format for screen width (using Base.print_matrix_row).

Just to recap: There is little or no problem with linspace or range being an object rather than array as far as execution goes. The only issue seems to be "unexpected" output at the REPL, where a user probably just wants to check what the range looks like, not its definition. Solution is to alter the REPL display to do that and provide the type information so the user doesn't think it's an array. The original show() behavior is retained, you can also dump() to see details of the range. I plan to submit a pull request.

Stefan Karpinski

unread,
Oct 9, 2015, 6:31:31 AM10/9/15
to Julia Users
It's amazing how often the problem is the way something is printed.

Luke Stagner

unread,
Oct 20, 2015, 9:03:52 PM10/20/15
to julia-users
Sorry to dredge up this issue again but was there any reason for the return type of linspace to be LinSpace instead of FloatRange. They are seemingly indistinguishable.

Yichao Yu

unread,
Oct 20, 2015, 9:12:15 PM10/20/15
to Julia Users
On Tue, Oct 20, 2015 at 9:03 PM, Luke Stagner <lstag...@gmail.com> wrote:
> Sorry to dredge up this issue again but was there any reason for the return
> type of linspace to be LinSpace instead of FloatRange. They are seemingly
> indistinguishable.

Not sure if this si **the** reason but you can't get linspace(0, 0,
100) with FloatRange.

Steven G. Johnson

unread,
Oct 20, 2015, 10:07:31 PM10/20/15
to julia-users


On Tuesday, October 20, 2015 at 9:03:52 PM UTC-4, Luke Stagner wrote:
Sorry to dredge up this issue again but was there any reason for the return type of linspace to be LinSpace instead of FloatRange. They are seemingly indistinguishable.

They are not quite the same because of roundoff differences; see e.g.


Basically, LinSpace is designed to give you a prescribed start/end points and length, whereas FloatRange is designed to give as close as possible to the spacing you prescribed.  See also the discussions in:

Art Kuo

unread,
Oct 20, 2015, 11:14:54 PM10/20/15
to julia-users
By the way, the original issue has been addressed and is now in master, see #13615. Ranges act the same internally, but REPL output looks like this: 

julia> 0:4
5-element UnitRange{Int64}:
 0,1,2,3,4

julia> 0:100
101-element UnitRange{Int64}:
 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,…,89,90,91,92,93,94,95,96,97,98,99,100

julia> linspace(0,2.5,4)
4-element LinSpace{Float64}:
 0.0,0.833333,1.66667,2.5

Stefan Karpinski

unread,
Oct 21, 2015, 12:44:15 PM10/21/15
to Julia Users
I *really* wish there was a way to collapse LinSpace and FloatRange into a single type, but I cannot for the life of me figure out how to do it without making both of them much slower.

Tom Breloff

unread,
Oct 21, 2015, 1:42:42 PM10/21/15
to julia-users
Call `collect` on them  ;)

Gabriel Gellner

unread,
Oct 21, 2015, 2:44:38 PM10/21/15
to julia-users
I agree with this downvote so much it hurts. The logspace/linspace is painfully ugly. linrange is the right name in my find for the iterator version.

On Wednesday, 30 September 2015 10:31:55 UTC-7, Alex Ames wrote:
Another downvote on linspace returning a range object. It seems odd for linspace and logspace to return different types, and linrange provides the low-memory option where needed. Numpy's `linspace` also returns an array object.
 I ran into errors when trying to plot a function over a linspace of x values, since plotting libs currently expect vectors as arguments, not range objects. Easily fixed if you know Julia well, but Matlab/Python converts may be stymied.

On Wednesday, September 30, 2015 at 12:19:22 PM UTC-5, J Luis wrote:
I want to add my voice to the dislikers. Those are the type of surprises that are not welcome mainly for matlab users.

quarta-feira, 30 de Setembro de 2015 às 16:53:57 UTC+1, Christoph Ortner escreveu:
I also strongly dislike the `linspace` change; I like the idea though of having `linspace` and `linrange`, where the former should give the array.
Christoph


On Wednesday, 30 September 2015 10:21:36 UTC+1, Michele Zaffalon wrote:
I just realize that the thread is about 0.3.11 and I am showing output for 0.4.0-rc2. Sorry for the noise.

On Wed, Sep 30, 2015 at 11:17 AM, Michele Zaffalon <michele....@gmail.com> wrote:

On Wed, Sep 30, 2015 at 9:50 AM, Milan Bouchet-Valat <nali...@club.fr> wrote:
Le mercredi 30 septembre 2015 à 08:55 +0200, Michele Zaffalon a écrit :
> Just curious: linspace returns a Range object, but logspace returns a
> vector because there is no much use case for a LogRange object?
>
> @feza: I have also seen the deprecation warning going away after a
> couple of calls, but I am not sure why. If you restart Julia, the
> deprecations reappear.
Deprecation warnings are only printed once for each call place. The
idea is that once you're aware of it, there's no point in nagging you.

Anyway, that warning is most probably not related to linspace at all,
but rather to the array concatenation syntax resulting in an effect
equivalent to collect(). If you show us a piece of code that prints the
warning, we can give you more details.


Regards

Sorry, you are right, I was referring to the concatenation.
It prints it exaclty twice if I type it in the REPL, it always prints it if I define it within a function e.g. a() = [1:3].

C:\Users\michele.zaffalon>julia
               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: http://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.4.0-rc2 (2015-09-18 17:51 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-w64-mingw32

julia> [1:3]
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in vect at abstractarray.jl:32
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> [1:3]
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in vect at abstractarray.jl:32
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> [1:3]
3-element Array{Int64,1}:
 1
 2
 3

julia> a() = [1:3]
a (generic function with 1 method)

julia> a()
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in a at none:1
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> a()
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in a at none:1
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3

julia> a()
WARNING: [a] concatenation is deprecated; use collect(a) instead
 in depwarn at deprecated.jl:73
 in oldstyle_vcat_warning at abstractarray.jl:29
 in a at none:1
while loading no file, in expression starting on line 0
3-element Array{Int64,1}:
 1
 2
 3
 

> On Wed, Sep 30, 2015 at 5:40 AM, feza <moham...@gmail.com> wrote:
> > Strange it *was* giving me an error saying deprecated and that I
> > should use collect, but now it's fine.
> >
> >
> > On Tuesday, September 29, 2015 at 10:28:12 PM UTC-4, Sheehan Olver
> > wrote:
> > > fez, I'm pretty sure the code works fine without the collect:
> > > when exp is called on linspace it converts it to a vector.
> > > Though the returned t will be linspace object.
> > >
> > > On Wednesday, September 30, 2015 at 12:10:55 PM UTC+10, feza
> > > wrote:
> > > > Here's the code I was using where I needed to use collect (I've
> > > > been playing around with Julia, so any suggestions on this code
> > > > for perf is welcome ;) ) . In general linspace (or the :
> > > > notation)  is also used commonly to lay  a grid in space for
> > > > solving a PDE for some other use cases.
> > > >
> > > > function gp(n)
> > > >         n = convert(Int,n)
> > > >         t0 = 0
> > > >         tf = 5
> > > >         t = collect( linspace(t0, tf, n+1) )
> > > >         sigma = exp( -(t - t[1]) )
> > > >
> > > >         c = [sigma; sigma[(end-1):-1:2]]
> > > >         lambda = fft(c)
> > > >         eta = sqrt(lambda./(2*n))
> > > >
> > > >         Z = randn(2*n) + im*randn(2*n)
> > > >         x = real( fft( Z.*eta ) )
> > > >         return (x, t)
> > > > end
> > > >
> > > >
> > > > On Tuesday, September 29, 2015 at 8:59:52 PM UTC-4, Stefan
> > > > Karpinski wrote:
> > > > > I'm curious why you need a vector rather than an object. Do
> > > > > you mutate it after creating it? Having linspace return an
> > > > > object instead of a vector was a bit of a unclear judgement
> > > > >  call so getting feedback would be good.
> > > > >
> > > > > On Tuesday, September 29, 2015, Patrick Kofod Mogensen <
> > > > > patrick....@gmail.com> wrote:
> > > > > > No:
> > > > > >
> > > > > > julia> logspace(0,3,5)
> > > > > > 5-element Array{Float64,1}:
> > > > > >     1.0
> > > > > >     5.62341
> > > > > >    31.6228
> > > > > >   177.828
> > > > > >  1000.0
> > > > > >
> > > > > > On Tuesday, September 29, 2015 at 8:50:47 PM UTC-4, Luke
> > > > > > Stagner wrote:
> > > > > > > Thats interesting. Does logspace also return a range?
> > > > > > >
> > > > > > > On Tuesday, September 29, 2015 at 5:43:28 PM UTC-7, Chris
> > > > > > > wrote:
> > > > > > > > In 0.4 the linspace function returns a range object,
> > > > > > > > and you need to use collect() to expand it. I'm also
> > > > > > > > interested in nicer syntax.


Stefan Karpinski

unread,
Oct 21, 2015, 3:16:58 PM10/21/15
to julia...@googlegroups.com
This thread is tragically long on opinions and short on arguments backing them up. It occurs to me that we can write specialized methods for collect(::LinSpace) that generate the collected version more efficiently than generic iteration does, which eliminates one of the potential arguments for just generating an array.

Art Kuo

unread,
Oct 21, 2015, 4:00:46 PM10/21/15
to julia-users
I don't think there is much to argue about, except perhaps names. 
  1. `linspace` returns a range, but is otherwise a drop-in replacement for an array, and should act as one for any naive user, other than sometimes being faster and taking less memory. This is not hidden from the user, yet they need not be concerned about it. It just works. (The array might be better in some cases, I suspect rarely.)
  2. One might expect a `linspace` to show an array when typed into the REPL. With #13615, post-0.4 the user will see that it is a range and also "what they expect."
  3. It is true that `logspace` is an array and `linspace` is a range, and this is ugly. Perhaps there should be a `logrange` to go with `linrange`, or `logspace` should be modified to be a range. I do agree with these complaints.
  4. The name `logspace` probably comes from Matlab, but otherwise has no significance and is not a great name. Perhaps it's worth keeping around for that reason; perhaps it should be stashed into a Matlab module.
  5. As much as I was attracted here by the Matlab-alikeness, that can be a detriment. For example, Matlab overloads `diag` so you get two very different things for two different inputs. Whereas Mathematica has long, clear names, and `DiagonalMatrix` and `Diagonal` give a better clue what will happen. And as much as I love `eye`, `IdentityMatrix` is clearer. Other Matlab-isms:  `tril`, `pcg`, `alim`, `shg`.

Sheehan Olver

unread,
Oct 21, 2015, 5:26:59 PM10/21/15
to julia...@googlegroups.com

I think much of the problem is that many necessary packages (e.g. for plotting) don’t currently allow Range/AbstractVector, and many functions in Base are slower for ranges than for vectors.  These are probably just teething problems, but until they are resolved “collect” ends up needing to be used a lot.

Michele Zaffalon

unread,
Nov 20, 2015, 7:54:50 AM11/20/15
to julia-users
Should `linspace` act as an array for `repeat`?

Milan Bouchet-Valat

unread,
Nov 20, 2015, 10:13:52 AM11/20/15
to julia...@googlegroups.com
Le vendredi 20 novembre 2015 à 04:54 -0800, Michele Zaffalon a écrit :
> Should `linspace` act as an array for `repeat`?
Yes, the signature of repeat() is clearly too strict. This has been
discussed at
https://github.com/JuliaLang/julia/issues/12953

There was a clear support for this, but a decision would have to be
taken regarding whether to use positional arguments instead of keyword
arguments.


Regards

Michele Zaffalon

unread,
Nov 22, 2015, 6:22:00 PM11/22/15
to julia...@googlegroups.com
Thank you, I should have checked the issues list first.
Reply all
Reply to author
Forward
0 new messages