2014-12-27 11 views
8

Ho un'applicazione in cui ho bisogno di definire una funzione a tratti, IE, f (x) = g (x) per [x in un intervallo], f (x) = h (x) per [x in qualche altro intervallo], ... ecc.Definisci funzioni a tratti in Julia

C'è un bel modo per farlo in Julia? Preferirei non usare if-else perché sembra che dovrei controllare ogni intervallo per grandi valori di x. Il modo in cui pensavo era costruire una serie di funzioni e una serie di limiti/intervalli, quindi quando viene chiamata f (x), eseguire una ricerca binaria sugli intervalli per trovare l'indice appropriato e utilizzare la funzione corrispondente (IE, h (x), g (x), ecc.

Sembra che un linguaggio matematicamente amichevole possa avere alcune funzionalità per questo, ma la documentazione non menziona in questo modo in qualche modo. qualche pensiero, grazie

+0

Si potrebbe voler esaminare l'implementazione della [funzione 'pezzata' di NumPy] (http://docs.scipy.org/doc/numpy/reference/generated/numpy.piecewise.html). – Jubobs

risposta

1

con una funzione di Heaviside si può fare una funzione di intervallo:!

function heaviside(t) 
    0.5 * (sign(t) + 1) 
end 

e

function interval(t, a, b) 
    heaviside(t-a) - heaviside(t-b) 
end 

function piecewise(t) 
    sinc(t) .* interval(t,-3,3) + cos(t) .* interval(t, 4,7) 
end 

e penso che potrebbe anche implementare un sottotipo di intervallo, sarebbe molto più elegante

1

ho cercato di implementare una funzione piecewise per Julia, e questo è il risultato:

function piecewise(x::Symbol,c::Expr,f::Expr) 
    n=length(f.args) 
    @assert n==length(c.args) 
    @assert c.head==:vect 
    @assert f.head==:vect 
    vf=Vector{Function}(n) 
    for i in 1:n 
    vf[i][email protected] $x->$(f.args[i]) 
    end 
    return @eval ($x)->($(vf)[findfirst($c)])($x) 
end 
pf=piecewise(:x,:([x>0, x==0, x<0]),:([2*x,-1,-x])) 
pf(1) # => 2 
pf(-2) # => 2 
pf(0) # => -1 
1

Perché non qualcosa del genere?

function piecewise(x::Float64, breakpts::Vector{Float64}, f::Vector{Function}) 
     @assert(issorted(breakpts)) 
     @assert(length(breakpts) == length(f)+1) 
     b = searchsortedfirst(breakpts, x) 
     return f[b](x) 
end 

piecewise(X::Vector{Float64}, bpts, f) = [ piecewise(x,bpts,f) for x in X ] 

Qui avete un elenco di punti di interruzione (ordinate), ed è possibile utilizzare il ottimizzato searchsortedfirst per trovare il primo punto di interruzione b maggiore di x. Il caso limite quando nessun punto di interruzione è maggiore diviene gestito in modo appropriato poiché viene restituito length(breakpts)+1, quindi b è l'indice corretto nel vettore di funzioni f.