I have two 1-D arrays in which I would like to calculate the approximate cumulative integral of 1 array with respect to the scalar spacing specified by the 2nd array. MATLAB has a function called cumtrapz that handles this scenario. Is there something similar that I can try within Julia to accomplish the same thing?
The expected result is another 1-D array with the integral calculated for each element.
There is a numerical integration package for Julia (see the link) that defines cumul_integrate(X, Y) and uses the trapezoidal rule by default.
If this package didn't exist, though, you could easily write the function yourself and have a very efficient implementation out of the box because the loop does not come with a performance penalty.
Edit: Added an #assert to check matching vector dimensions and fixed a typo.
function cumtrapz(X::T, Y::T) where {T <: AbstractVector}
# Check matching vector length
#assert length(X) == length(Y)
# Initialize Output
out = similar(X)
out[1] = 0
# Iterate over arrays
for i in 2:length(X)
out[i] = out[i-1] + 0.5*(X[i] - X[i-1])*(Y[i] + Y[i-1])
end
# Return output
out
end
Related
I have functions f1 and f2 returning matrices m1 and m2, which are calculated using Diagonal, Tridiagonal, SymTridiagonal from LinearAlgebra package.
In a new function f3 I try computing
j = m1 - m2*im
m3 = exp(j)
but this gives a Method error on computation unless I use j=Matrix(m1-m2*im), saying that no matching method for exp(::LinearAlgebra.Tridiagonal ...)
My question is how can I do this computation in the most optimal way? I am a total beginner in Julia.
Unless you have a very special structure of j (i.e. if its exponential is sparse - which is unlikely) the best you can do AFAICT is to use a dense matrix as an input to exp:
m3 = LinearAlgebra.exp!([float(x) for x in Tridiagonal(dl, d, du)])
If you expect m3 to be sparse then I think currently there is no special algorithm implemented for that case in Julia.
Note that I use exp! to do operation in place and use a comprehension to make sure the argument to exp! is dense. As exp! expects LinearAlgebra.BlasFloat (that is Union{Complex{Float32}, Complex{Float64}, Float32, Float64}) I use float to make sure that elements of j are appropriately converted. Note that it might fail if you work with e.g. BigFloat or Float16 values - in this case you have to do an appropriate conversion to the expected types yourself.
I have some code which I call with two vectors of different length, lets call them A and B. However, I wrote the function having in mind a single element of A with the expectation that it will be automatically threaded over A. To be concrete,
A <- rnorm(5)
B <- rnorm(30)
foo <- function(x,B){
sum( cos(x*B) ) # calculate sum_i cos(x*B[i])
}
sum( exp(foo(A,B)) ) # expecting this to calculate the exponent for each A[j] and add over j
I need to get
Σ_j exp( Σ_i cos(A[j]*B[i])
and not
Σ_ij exp(cos(A[j]*B[i])) OR exp(cos(Σ_ij A[j]*B[i]))
I suspect that the last R expression is ambiguous, since the declaration of foo does not know B is always a vector. What are the formal rules and am I right to worry about the ambiguity?
If we want to loop over the 'A', then use sapply , and apply the foo on each of the elements of 'A' with anonymous function call and get the sum of the output vector
sum(exp(sapply(A, function(x) foo(x, B))))
In the OP's example with the expression foo(A, B), the product A*B is computed first, and since the lengths of A and B are unequal, the recycling rule takes priority. There is no error message coming out, just because by pure luck the vector length of one is a multiple of the other.
You can also Vectorize the x input. I think this is what you were expecting. At the end of the day, this will work it's way down to an mappy() implementation which is a multivariate sapply, so probably best to just do it yourself as with the solution from akrun.
foo2 <- Vectorize(foo, "x")
sum(exp(foo2(A, B)))
The "formal rules" as you put them is quite simply how R does help("Arithmetic").
The binary operators return vectors containing the result of the element by element operations. If involving a zero-length vector the result has length zero. Otherwise, the elements of shorter vectors are recycled as necessary (with a warning when they are recycled only fractionally). The operators are + for addition, - for subtraction, * for multiplication, / for division and ^ for exponentiation.
So when you use x*B, it is doing element-wise multiplication. Nothing changes when you pass A into the function instead of x.
Simply go through your lines one at a time.
x*B will be a vector of length max(length(x, B)). When they are not of the same length, R will recycle elements of the shorter vector (i.e., repeat them).
cos(x*B) will be a vector of the same length as step (1), but now the cosine of that value.
sum( cos(x*B) ) will sum that vector, returning a single number.
foo(A,B) does steps (1) through (3), but with your defined A and B. Note that in your example A is recycled 6 times to get to the length of B. In other words, what you entered as A is being used as rep(A, 6) in the multiplication step. Nothing about a function definition in R says that foo(A,B) should be repeated for each element of vector A. So it behaves literally as you wrote it, basically swapping in A for x in the function code.
exp(foo(A,B)) will take the result from foo from step 3 (which is a scalar) and raise it to an exponent.
sum( exp(foo(A,B)) ) does nothing, since step (5) is a scalar, there is nothing to sum.
using ShiftedArrays
struct CircularMatrix{T} <: AbstractArray{T,2}
data::Array{T,2}
view::CircShiftedArray
currentIndex::Int
function CircularMatrix{T}(dims...) where T
data = zeros(T, dims...)
CircularMatrix(data, ShiftedArrays.circshift(data, (0, -1)), 1)
end
end
Base.size(M::CircularMatrix) = size(M.data)
Base.eltype(::Type{CircularMatrix{T}}) where {T} = T
function shift_forward!(M::CircularMatrix)
M.shift_forward!(1)
end
function shift_forward!(M::CircularMatrix, n)
# replace the view with a view shifted forwards.
M.currentIndex += n
M.view = ShiftedArrays.circshift(M.data, (n, M.currentIndex))
end
#inline Base.#propagate_inbounds function Base.getindex(M::CircularMatrix, i) = M.view[i]
#inline Base.#propagate_inbounds function Base.setindex!(M::CircularMatrix, data, i) = M.view[i] = data
How can I make CircularMatrix act just like a regular matrix.
So that I can access it like
m = CircularMatrix{Int}(4,4)
m[1, 1] = 5
x = view(m, 1, :)
Your matrix type is defined to be a subtype of AbstractArray{T, 2}. You need to implement a few methods in the informal array interface of Julia for your type to make functions and features that work on AbstractArray{T, 2} to also work on your custom type, that is, to make your CircularMatrix an iterable, indexable, completely functioning matrix.
The methods to implement are
size(M::CircularMatrix)
getindex(M::CircularMatrix, i::Int)
getindex(M::CircularMatrix, I::Vararg{Int, N})
setindex!(M::CircularMatrix, v, i::Int)
setindex!(M::CircularMatrix, v, I::Vararg{Int, N})
You already implement 1, 2 and 4 but have not yet set your indexing style. You might not need 3 and 5 if you choose linear indexing style. You only need to set IndexStyle to be IndexLinear() and maybe a few modifications, then everything should just work for your matrix.
1. size(M::CircularMatrix)
The first one is size. size(A::CircularMatrix) returns a Tuple of dimensions of A. I believe for your matrix probably something like the following
Base.size(M::CircularMatrix) = size(M.data)
2. getindex(M::CircularMatrix, i::Int)
This method is needed if you choose linear indexing style. getindex(M, i::Int) should give you the value at linear index i. You already implement it in your code. If you choose linear indexing, you need to set IndexStyle for your type and then you simply skip 3 and 5. Julia will automatically convert multiple index accesses, e.g. a[3, 5], to a linear index access.
Base.IndexStyle(::Type{<:CircularMatrix}) = IndexLinear()
Base.#propogate_inbounds function Base.getindex(M::CircularMatrix, i::Int)
#boundscheck checkbounds(M, i)
#inbounds M.view[i]
end
It might be better to use #inbounds here on the second line. If the caller doesn't use #inbounds, we check the bounds first and this hopefully makes the subsequent bounds check unnecessary. You might want to omit this during development, though.
3. getindex(M::CircularMatrix, I::Vararg{Int, N})
The third one is for Cartesian indexing style. If you choose this style you need to implement this method. Vararg{Int, N} in the signature stands for "exactly N Int arguments". Here N should be equal to the dimensionality of CircularMatrix. Since this is a matrix, N should be two. If you choose this style, you need to define something like the following
Base.#propogate_inbounds function Base.getindex(A::CircularMatrix, I::Vararg{Int, 2})
#boundscheck checkbounds(A, I...)
#inbounds A.view[# convert I[1]` and `I[2]` to a linear index in `view`]
end
or since your dimensionality is not parametric and a matrix is 2D, simply
Base.#propogate_inbounds function Base.getindex(A::CircularMatrix, i::Int, j::Int)
#boundscheck checkbounds(A, i, j)
#inbounds A.view[# convert i` and `j` to a linear index in `view`]
end
4. setindex!(M::CircularMatrix, v, i::Int)
The fourth one is similar to the second. This method should set the value at linear index i, if you choose linear indexing style.
5. setindex!(M::CircularMatrix, v, I::Vararg{Int, N})
The fifth one should be similar to the third, if you choose Cartesian indexing style.
After the implementations for 1, 2, and 4 and setting IndexStyle, you should have a custom matrix type that just works.
m[1, 1] = 5
x = view(m, 1, :)
for e in
...
end
for i in eachindex(m)
...
end
display(m)
println(m)
length(m)
ndims(m)
map(f, A)
....
These should all work.
A few notes
There is a documentation for Abstract Arrays interface here with a few examples. You can also see Optional Methods to implement.
There is a JuliaArray organization on GitHub that provides lots of useful custom array implementations including StaticArrays, OffsetArrays, etc. and also a JuliaMatrices organization that provides custom matrix types. You might want to take a look at their implementations.
#inline is redundant if you use Base.#propogate_inbounds.
#propagate_inbounds
Tells the compiler to inline a function while retaining the caller's
inbounds context.
You do not need to define eltype for your matrix, since there is already a definition for AbstractArray{T, N} which returns T.
The Question: I was hoping to find a function like findInterval in R which gives inputs a scalar and a vector representing interval starting points and returns the index of what interval the scalar falls in. For instance in R:
findInterval(x = 2.6, vec = c(1.1,2.1,3.1,4.1))
#[1] 2
In this exchange someone gave a function that does this functionality in Julia (See next section). Apparently the base indexin function does this task though. I was wondering how to get indexin function (or another base function) to do this. I know Julia loops are fast and I could write a function but I would rather not do that if there is an inbuilt function and this should be a common problem.
When I try the indexin function with the same numbers I used in R above I get:
indexin([2.6], [1.1 2.1 3.1 4.1])
# 1-element Array{Int64,1}:
# 0
Which just indicates that 2.6 is not in the vector as it (as I understand) is looking to match values rather than placing a scaler in an interval.
Function from above referenced link (with my changes to input\output datatypes)
function findInterval(x::Float64,vec::Array{Float64})
out = zeros(Int,length(x))
vec = unique(vec)
sort!(vec)
for j in 1:length(x)
if x[j] < vec[1]
out[1] = 0
elseif x[j] > vec[end]
out[end] = 0
else
out[j] = searchsortedfirst(vec,x[j])-1
end
end
return out
end
Which works as intended:
findInterval(2.6, [1.1 2.1 3.1 4.1])
# 1-element Array{Int64,1}:
# 2
Related Questions from SO: Other questions on SO look for finding the index of exact matches between an input value and a vector:
Julia version of R's Match?
Find first index of an item in an array in Julia
Vectorized "in" function in julia?
If your input vector is always sorted, then searchsortedlast will do what you want, e.g.
vec = [1.1, 2.1, 3.1, 4.1]
x = 2.6
searchsortedlast(vec, x)
However, note that searchsortedlast will return 0 if x < vec[1], and will return length(vec) if x > vec[end]. So you might want to write your own custom behaviour that checks for these outcomes, e.g. if you want to always return 0 if x is not in any of the intervals in vec, you could write:
function find_interval(vec, x)
i = searchsortedlast(vec, x)
i == length(vec) && (i = 0)
return(i)
end
Also, if you work a lot with sorted vectors, you might be interested in a package I've written for sorted vectors in Julia, but have never gotten around to adding to METADATA. The source of SortedVectors package is here.
I have an application in which I need to define a piecewise function, IE, f(x) = g(x) for [x in some range], f(x)=h(x) for [x in some other range], ... etc.
Is there a nice way to do this in Julia? I'd rather not use if-else because it seems that I'd have to check every range for large values of x. The way that I was thinking was to construct an array of functions and an array of bounds/ranges, then when f(x) is called, do a binary search on the ranges to find the appropriate index and use the corresponding function (IE, h(x), g(x), etc.
It seems as though such a mathematically friendly language might have some functionality for this, but the documentation doesn't mention piecewise in this manner. Hopefully someone else has given this some thought, thanks!
with a Heaviside function you can do a interval function:
function heaviside(t)
0.5 * (sign(t) + 1)
end
and
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
and I think it could also implement a subtype Interval, it would be much more elegant
I tried to implement a piecewise function for Julia, and this is the result:
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]=#eval $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
Why not something like this?
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 ]
Here you have a list of (sorted) breakpoints, and you can use the optimized searchsortedfirst to find the first breakpoint b greater than x. The edge case when no breakpoint is greater than x is also handled appropriately since length(breakpts)+1 is returned, so b is the correct index into the vector of functions f.