2017-10-26 7 views
1

Ich bin neu zu Julia und ich versuche, eine Funktion über eine Reihe von Werten zu plotten, die ich selbst mit Gadfly definiert. Die Funktion selbst ist ziemlich einfach.InexactError geworfen von Gadfly abhängig von der Reihenfolge der Werte

function metropolis(dU, b) 
    if dU < 0 
     1 
    else 
     exp(-dU * b) 
    end 
end 

Wenn ich versuche, um diese Funktion zu plotten ich ein InexactError von julia geworfen.

using Gadfly 
x = linspace(-5, 5, 100) 
b = 1 
plot(x=x, y=metropolis.(x, b), Geom.line) 

Der genaue Fehler ist

Stacktrace: 
[1] apply_scale_typed!(::Array{Int64,1}, ::Array{Real,1}, ::Gadfly.Scale.ContinuousScale) at /home/max/.julia/v0.6/Gadfly/src/scale.jl:249 
[2] apply_scale(::Gadfly.Scale.ContinuousScale, ::Array{Gadfly.Aesthetics,1}, ::Gadfly.Data, ::Vararg{Gadfly.Data,N} where N) at /home/max/.julia/v0.6/Gadfly/src/scale.jl:206 
[3] apply_scales(::IterTools.Distinct{Base.ValueIterator{Dict{Symbol,Gadfly.ScaleElement}},Gadfly.ScaleElement}, ::Array{Gadfly.Aesthetics,1}, ::Gadfly.Data, ::Vararg{Gadfly.Data,N} where N) at /home/max/.julia/v0.6/Gadfly/src/scale.jl:33 
[4] apply_scales(::IterTools.Distinct{Base.ValueIterator{Dict{Symbol,Gadfly.ScaleElement}},Gadfly.ScaleElement}, ::Gadfly.Data) at /home/max/.julia/v0.6/Gadfly/src/scale.jl:52 
[5] render_prepare(::Gadfly.Plot) at /home/max/.julia/v0.6/Gadfly/src/Gadfly.jl:670 
[6] render(::Gadfly.Plot) at /home/max/.julia/v0.6/Gadfly/src/Gadfly.jl:748 
[7] show at /home/max/.julia/v0.6/Gadfly/src/Gadfly.jl:952 [inlined] 
[8] limitstringmime(::MIME{Symbol("image/svg+xml")}, ::Gadfly.Plot) at /home/max/.julia/v0.6/IJulia/src/inline.jl:24 
[9] display_dict(::Gadfly.Plot) at /home/max/.julia/v0.6/IJulia/src/execute_request.jl:29 
[10] execute_request(::ZMQ.Socket, ::IJulia.Msg) at /home/max/.julia/v0.6/IJulia/src/execute_request.jl:182 
[11] eventloop(::ZMQ.Socket) at /home/max/.julia/v0.6/IJulia/src/eventloop.jl:8 
[12] (::IJulia.##14#17)() at ./task.jl:335 

Aber seltsam, wenn ich -x verwenden es funktioniert

plot(x=x, metropolis.(-x, b), Geom.line) 

Dies wird nur die Reihenfolge der Werte umzukehren. Dieses Verhalten ist mir sehr fremd. Ich schätze jede Hilfe.

+0

Die Antwort, die Sie gegeben haben, erklärt die Situation gut. Aber, FYI, eine nette Art, Ihre Funktion zu schreiben, ist einfach: 'metropolis (dU, b) = dU <0? 1.0: Float64 (exp (-dU * b)) '. Dies ist nun typestabil, da die Rückkehr von dem "exp" -Aufruf, wenn möglich, immer in "Float64" umgewandelt wird, oder andernfalls, wenn z. eine Ihrer Eingaben in 'Complex'. Wenn Sie auf Eingaben wie "Complex" stoßen, besteht die einfachste Lösung darin, einfach eine zweite Methode hinzuzufügen, die sich explizit mit diesem Fall befasst. –

Antwort

3

Der Grund ist, dass Ihre Funktion nicht typstabil ist - ihr Rückgabewert hängt von den Werten der Argumente und nicht nur von ihren Typen ab. Hier ist die einfachste (aber nicht die schnellste) fixieren Sie eine richtige Art und Weise, welche die Funktion zu kodieren:

function metropolis(dU, b) 
    if dU < 0 
     zero(exp(-dU * b)) 
    else 
     exp(-dU * b) 
    end 
end 

Allgemein - sicherzustellen, dass beide Zweige der if-else die gleiche Art zurück.

Der Grund, dass Gadfly ist diesen Teil des Codes aufgrund fehlschlägt: https://github.com/GiovineItalia/Gadfly.jl/blob/master/src/scale.jl#L194

und wahrscheinlich festgelegt werden soll, wie es break auf dem ersten konkreten Typ durchführt, die für tatsächlich eine falsche Entscheidung.

+0

Gibt es eine Möglichkeit, eine Variable vom Typ T in der Funktion zu konstruieren, wenn ich die Signatur "metropolis {T <: Real} (dU :: T, b :: T)" verwende? –

+0

Die richtige Signatur in der aktuellen Julia ist 'metropolis (dU :: T, b :: T) wo T <: Real '. Dann können Sie alles innerhalb einer Funktion in 'T' umwandeln, indem Sie' T ([irgendein Wert]) 'schreiben. Beachten Sie jedoch, dass "exp" nicht den Wert des Typs "T" zurückgeben muss, wenn sowohl "dU" als auch "b" vom Typ "T" sind, z. 'exp (1)' ist 'Float64', obwohl sein Argument' Int' ist. –

Verwandte Themen