In MatLab/Octave you could send a command "format long g" and have default numerical output in the REPL formatted like the following:
octave> 95000/0.05
ans = 1900000
Is it possible to get a similar behavior in Julia? Currently with julia
Version 0.3.0-prerelease+3930 (2014-06-28 17:54 UTC)
Commit bdbab62* (6 days old master)
x86_64-redhat-linux
I get the following number format.
julia> 95000/0.05
1.9e6
You can use the #printf macro to format. It behaves like the C printf, but unlike printf for C the type need not agree but is rather converted as necessary. For example
julia> using Printf
julia> #printf("Integer Format: %d",95000/0.05);
Integer Format: 1900000
julia> #printf("As a String: %s",95000/0.05);
As a String: 1.9e6
julia> #printf("As a float with column sized larger than needed:%11.2f",95000/0.05);
As a float with column sized larger than needed: 1900000.00
It is possible to use #printf as the default mechanism in the REPL because the REPL is implemented in Julia in Base.REPL, and in particular the following function:
function display(d::REPLDisplay, ::MIME"text/plain", x)
io = outstream(d.repl)
write(io, answer_color(d.repl))
writemime(io, MIME("text/plain"), x)
println(io)
end
To modify the way Float64 is displayed, you merely need to redefine writemime for Float64.
julia> 95000/0.05
1.9e6
julia> Base.Multimedia.writemime(stream,::MIME"text/plain",x::Float64)=#printf("%1.2f",x)
writemime (generic function with 13 methods)
julia> 95000/0.05
1900000.00
Related
In Julia, I can easily create a graph using the very nicely written Graphs.jl library:
julia> using Graphs
julia> g = SimpleDiGraph(2)
{2, 0} directed simple Int64 graph
julia> add_edge!(g, 1,2)
true
julia> add_edge!(g, 2, 1)
true
However, I cannot seem to make the nodes anything other than integers. To wit, I would like to do something like this:
julia> using Graphs
julia> abstract type Foo end
julia> s = SimpleDiGraph(typeof(Foo)) # doesn't work.
julia> mutable struct Bar <: Foo
b::Bool
end
julia> mutable struct Baz <: Foo
b::Bool
end
julia> bar = Bar(true)
Bar(true)
julia> baz = Baz(false)
Baz(false)
julia> add_edge!(g, bar, baz) # Again, doesn't work.
How can I make the nodes a custom type?
Note: I have tried the following workaround, as it appears that only integral types are allowed in the nodes:
julia> add_edge!(g, Int64(pointer_from_objref(bar)), Int64(pointer_from_objref(baz)))
but this one, although not throwing an exception, returns false.
In the Graphs.jl tutorial, it is stated that "integers, and only integers, may be used for describing vertices." So my first goal is out of the question (although it may be possible in, say, MetaGraphs.jl). The recommendation is to use the integer value in the vertex as an index into a vector and store the objects in the vector.
Moreover, as it is stated that the goal is to index into a vector, the integers must be contiguous, and hence my second idea of using the address of the object is also not feasible.
However, using the graph to index into a vector is a perfectly acceptable solution for me.
Is there in Julia a Collection type from which both Set and Array derive ?
I have both:
julia> supertype(Array)
DenseArray{T,N} where N where T
julia> supertype(DenseArray)
AbstractArray{T,N} where N where T
julia> supertype(AbstractArray)
Any
And:
julia> supertype(Set)
AbstractSet{T} where T
julia> supertype(AbstractSet)
Any
What I try to achieve is to write function that can take both Array or Set as argument, because the type of collection doesn't matter as long as I can iterate over it.
function(Collection{SomeOtherType} myCollection)
for elem in myCollection
doSomeStuff(elem)
end
end
No, there is no Collection type, nor is there an Iterable one.
In theory, what you ask can be accomplished through traits, which you can read about elsewhere. However, I would argue that you should not use traits here, and instead simply refrain from restricting the type of your argument to the function. That is, instead of doing
foo(x::Container) = bar(x)
, do
foo(x) = bar(x)
There will be no performance difference.
If you want to restrict your argument types you could create a type union:
julia> ty = Union{AbstractArray,AbstractSet}
Union{AbstractSet, AbstractArray}
julia> f(aarg :: ty) = 5
f (generic function with 1 method)
This will work on both sets and arrays
julia> f(1:10)
5
julia> f(rand(10))
5
julia> f(Set([1,2,5]))
5
But not on numbers, for example
julia> f(5)
ERROR: MethodError: no method matching f(::Int64)
Closest candidates are:
f(::Union{AbstractSet, AbstractArray}) at REPL[2]:1
I wanted make a macro that creates some code for me. E.g.
I have a vector x = [9,8,7] and I want to use a macro to generate this piece of code vcat(x[1], x[2], x[3]) and run it. And I want it to work for arbitrary length vectors.
I have made the macro as below
macro some_macro(a)
quote
astr = $(string(a))
s = mapreduce(aa -> string(astr,"[",aa,"],"), string, 1:length($(a)))
eval(parse(string("vcat(", s[1:(end-1)],")")))
end
end
x = [7,8,9]
#some_macro x
The above works. But when I try to wrap it inside a function
function some_fn(y)
#some_macro y
end
some_fn([4,5,6])
It doesn't work and gives error
UndefVarError: y not defined
and it highlights the below as the culprit
s = mapreduce(aa -> string(astr,"[",aa,"],"), string, 1:length($(a)))
Edit
See julia: efficient ways to vcat n arrays
for advanced example why I want to do instead of using the splat operator
You don't really need macros or generated functions for this. Just use vcat(x...). The three dots are the "splat" operator — it unpacks all the elements of x and passes each as a separate argument to vcat.
Edit: to more directly answer the question as asked: this cannot be done in a macro. Macros are expanded at parse time, but this transformation requires you to know the length of the array. At global scope and in simple tests it may appear that it's working, but it's only working because the argument is defined at parse time. In a function or in any real use-cases, however, that's not the case. Using eval inside a macro is a major red flag and really shouldn't be done.
Here's a demo. You can create a macro that vcats three arguments safely and easily. Note that you should not construct strings of "code" at all here, you can just construct an array of expressions with the :( ) expression quoting syntax:
julia> macro vcat_three(x)
args = [:($(esc(x))[$i]) for i in 1:3]
return :(vcat($(args...)))
end
#vcat_three (macro with 1 method)
julia> #macroexpand #vcat_three y
:((Main.vcat)(y[1], y[2], y[3]))
julia> f(z) = #vcat_three z
f([[1 2], [3 4], [5 6], [7 8]])
3×2 Array{Int64,2}:
1 2
3 4
5 6
So that works just fine; we esc(x) to get hygiene right and splat the array of expressions directly into the vcat call to generate that argument list at parse time. It's efficient and fast. But now let's try to extend it to support length(x) arguments. Should be simple enough. We'll just need to change 1:3 to 1:n, where n is the length of the array.
julia> macro vcat_n(x)
args = [:($(esc(x))[$i]) for i in 1:length(x)]
return :(vcat($(args...)))
end
#vcat_n (macro with 1 method)
julia> #macroexpand #vcat_n y
ERROR: LoadError: MethodError: no method matching length(::Symbol)
But that doesn't work — x is just a symbol to the macro, and of course length(::Symbol) doesn't mean what we want. It turns out that there's absolutely nothing you can put there that works, simply because Julia cannot know how large x is at compile time.
Your attempt is failing because your macro returns an expression that constructs and evals a string at run-time, and eval does not work in local scopes. Even if that could work, it'd be devastatingly slow… much slower than splatting.
If you want to do this with a more complicated expression, you can splat a generator: vcat((elt[:foo] for elt in x)...).
FWIW, here is the #generated version I mentioned in the comment:
#generated function vcat_something(x, ::Type{Val{N}}) where N
ex = Expr(:call, vcat)
for i = 1:N
push!(ex.args, :(x[$i]))
end
ex
end
julia> vcat_something(x, Val{length(x)})
5-element Array{Float64,1}:
0.670889
0.600377
0.218401
0.0171423
0.0409389
You could also remove #generated prefix to see what Expr it returns:
julia> vcat_something(x, Val{length(x)})
:((vcat)(x[1], x[2], x[3], x[4], x[5]))
Take a look at the benchmark results below:
julia> using BenchmarkTools
julia> x = rand(100)
julia> #btime some_fn($x)
190.693 ms (11940 allocations: 5.98 MiB)
julia> #btime vcat_something($x, Val{length(x)})
960.385 ns (101 allocations: 2.44 KiB)
The huge performance gap is mainly due to the fact that #generated function is firstly executed and executed only once at compile time(after the type inference stage) for each N that you passed to it. When calling it with a vector x having the same length N, it won't run the for-loop, instead, it'll directly run the specialized compiled code/Expr:
julia> x = rand(77); # x with a different length
julia> #time some_fn(x);
0.150887 seconds (7.36 k allocations: 2.811 MiB)
julia> #time some_fn(x);
0.149494 seconds (7.36 k allocations: 2.811 MiB)
julia> #time vcat_something(x, Val{length(x)});
0.061618 seconds (6.25 k allocations: 359.003 KiB)
julia> #time vcat_something(x, Val{length(x)});
0.000023 seconds (82 allocations: 2.078 KiB)
Note that, we need to pass the length of x to it ala a value type(Val), since Julia can't get that information(unlike NTuple, Vector only has one type parameter) at compile time.
EDIT:
see Matt's answer for the right and simplest way to solve the problem, I gonna leave the post here since it's relevant and might be helpful when dealing with splatting penalty.
Is it possible to create a function which takes a ::Vector{DataType} but constrains all members to be types which inherit from a particular abstract type?
Example:
# this code works but does not constrain the type
function foo{D<:DataType}(arr::Vector{D})
...
end
# this is kind of the syntax I'd like, but Type{Int} !<: Type{Integer}
function bar{D<:Type{Integer}}(arr::Vector{D})
...
end
Thank you
I'm not sure this is possible (cleanly) with a compile-time check. You could consider using a Val type, but this will be messy and probably slower. I would just make it a run-time check:
julia> function bar{T}(::Type{T}, arr::Vector{DataType})
if all(x->x<:T, arr)
println("ok")
else
println("bad")
end
end
bar (generic function with 1 method)
julia> bar(Integer, [Int,Int32])
ok
julia> bar(Integer, [Int,Int32,Float64])
bad
What's your use case for this? There might be an alternative that's cleaner.
just to clarify why function bar{T<:Integer}(arr::Vector{Type{T}}) = println(arr) won't work.
in a nutshell, this is because julia's type parameter is invariant.
firstly, take a look a OP's definition:
function bar{D<:Type{Integer}}(arr::Vector{D})
...
end
the problem here, as OP pointed out, is Type{Int} !<: Type{Integer}.
the reason is that Type{T} is a parametric type, even though Int <: Integer, we don't have Type{Int} <: Type{Integer}.
"bearing in mind"(yes, that's sarcasm) that the type parameter of julia's parametric type is invariant, i suggested to use this version:
function bar{T<:Integer}(arr::Vector{Type{T}})
...
end
it seems good! this time i'm using T instead of Type{T}, so i won't fall into the pit of Type{Int} !<: Type{Integer}.
however, as i wrote down that comment, i had just fallen into another pit -- Vector{} is also a parametric type. even if DataType <: Type{T}, we don't have Vector{DataType} <: Vector{Type{T}}.
as a result, a error will occur when running bar([Int64, Int32]).
julia> bar([Int64, Int32])
ERROR: MethodError: `bar` has no method matching bar(::Array{DataType,1})
julia> methods(bar)
bar{T<:Integer}(arr::Array{Type{T<:Integer},1})
julia> [Int64, Int32]
2-element Array{DataType,1}:
Int64
Int32
EDIT:
hmm, it seems that this problem is not that simple. the key point here is the mysterious relationship between DataType and Type{T}.
# we know that DataType is a subtype of Type{T},
# where T is a `TypeVar` \in [Bottom, Any].
julia> subtypes(Type)
3-element Array{Any,1}:
DataType
TypeConstructor
Union
julia> S = TypeVar(:S, Union{}, Integer, true)
S<:Integer
# but Type{S} is not a subtype of DataType
julia> Type{S} <: DataType
false
julia> Type{S} <: Type
true
i therefore conclude that it's impossible to make ::Vector{DataType} work in your case.
DataType has NO type parameters.
the below definition won't work, which seems like a bug.
julia> a = Array(Type{S}, 2)
2-element Array{Type{S<:Integer},1}:
#undef
#undef
julia> a[1] = Type{Int32} # or Int32
Type{Int32}
julia> a[2] = Type{Float32} # or Float32
Type{Float32}
julia> a
2-element Array{Type{S<:Integer},1}:
Type{Int32}
Type{Float32}
i'll post a question about this strange behavior. #Mageek
According to http://julia.readthedocs.org/en/latest/manual/integers-and-floating-point-numbers/, one should be able to do this:
julia> Float32(-1.5)
-1.5f0
Instead, I get:
julia> Float32(-1.5)
ERROR: type cannot be constructed
This happens for all other attempts to use this syntax, e.g. x = Int16(1)
I'm on 0.3.10.
You are on 0.3.10 but reading the manual for 0.5. In the manual for 0.3 http://julia.readthedocs.org/en/release-0.3/manual/integers-and-floating-point-numbers/
Values can be converted to Float32 easily:
julia> float32(-1.5)
-1.5f0
julia> typeof(ans)
Float32