Skip to content

Commit

Permalink
fix integration
Browse files Browse the repository at this point in the history
  • Loading branch information
EigenSolver committed Sep 3, 2024
1 parent 0de3ca3 commit ee820b7
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 111 deletions.
20 changes: 10 additions & 10 deletions src/integration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ increment `h`
# Arguments
- `y::Vector{<:Real}`: f(x).
- `h::Real`: the step of integral.
- `method::Symbol=:trapezoid`: the method of integration
- `method::Symbol=:simpson`: the method of integration
"""
function integrate(y::ArrayOrSubArray{<:Real,1}, h::Real; method::Symbol=:trapezoid)::Real
function integrate(y::ArrayOrSubArray{<:Real,1}, h::Real; method::Symbol=:simpson)::Real
n = length(y) - 1
if n%2==1
println("warning: `y` length (number of intervals) must be odd, switching to first order integration.")
Expand All @@ -37,7 +37,7 @@ end
- `a::Real`: The lower bound of the integration range.
- `b::Real`: The upper bound of the integration range.
- `n::Int`: The number of points at which to evaluate `f(x)`. For Simpson's rule, `n` should be an odd number.
- `method::Symbol=:trapezoid`: The numerical integration method to use. Options are `:simpson` for Simpson's rule and `:trapezoid` for the Trapezoidal rule.
- `method::Symbol=:simpson`: The numerical integration method to use. Options are `:simpson` for Simpson's rule and `:trapezoid` for the Trapezoidal rule.
# Returns
- `Real`: The estimated value of the integral of `f(x)` over [a, b].
Expand All @@ -48,13 +48,13 @@ result = integrate(sin, 0, π, 101, method=:simpson)
```
"""
function integrate(f::Function, a::Real, b::Real, n::Int;
method::Symbol=:trapezoid)::Real
method::Symbol=:simpson)::Real
h = (b - a) / (n - 1)
y = f.(range(a, b, n))
return integrate(y, h, method=method)
end

function integrate(f::Function, x_range::Tuple{Real,Real,Int}; method::Symbol=:trapezoid)::Real
function integrate(f::Function, x_range::Tuple{Real,Real,Int}; method::Symbol=:simpson)::Real
return integrate(f, x_range..., method=method)
end

Expand All @@ -65,7 +65,7 @@ end
- `f::Function`: The function to be integrated. It should accept two real numbers (x, y) and return a real number.
- `x_range::Tuple{Real, Real, Int}`: A tuple representing the range and number of points for the x-dimension: (x_min, x_max, num_points_x).
- `y_range::Tuple{Real, Real, Int}`: A tuple representing the range and number of points for the y-dimension: (y_min, y_max, num_points_y).
- `method::Symbol=:trapezoid`: The numerical integration method to use. Options are `:simpson` for Simpson's rule and `:trapezoid` for the Trapezoidal rule.
- `method::Symbol=:simpson`: The numerical integration method to use. Options are `:simpson` for Simpson's rule and `:trapezoid` for the Trapezoidal rule.
# Returns
- `Real`: The estimated value of the integral of `f(x, y)` over the defined 2D area.
Expand All @@ -76,7 +76,7 @@ result = integrate((x, y) -> x * y, (0, 1, 50), (0, 1, 50), method=:simpson)
```
"""
function integrate(f::Function, x_range::Tuple{Real,Real,Int}, y_range::Tuple{Real,Real,Int};
method::Symbol=:trapezoid)::Real
method::Symbol=:simpson)::Real
g = y -> integrate(x -> f(x, y), x_range, method=method)
return integrate(g, y_range, method=method)
end
Expand All @@ -89,18 +89,18 @@ increments `h_x` and `h_y`.
- `z::Matrix{<:Real}`: f(x, y).
- `h_x::Real`: the step size of the integral in the x direction.
- `h_y::Real`: the step size of the integral in the y direction.
- `method::Symbol=:trapezoid`: the method of integration.
- `method::Symbol=:simpson`: the method of integration.
...
"""
function integrate(z::ArrayOrSubArray{<:Real,2}, h_x::Real, h_y::Real; method::Symbol=:trapezoid)::Real
function integrate(z::ArrayOrSubArray{<:Real,2}, h_x::Real, h_y::Real; method::Symbol=:simpson)::Real
nrows, ncols = size(z)
# Integrate along x direction for each y
integral_x_direction = [integrate((@view z[:, j]), h_x, method=method) for j = 1:ncols]
# Integrate the result in y direction
return integrate(integral_x_direction, h_y, method=method)
end

integrate(z::ArrayOrSubArray{<:Real,2}, h; method::Symbol=:trapezoid) = integrate(z, h, h; method=method)
integrate(z::ArrayOrSubArray{<:Real,2}, h; method::Symbol=:simpson) = integrate(z, h, h; method=method)

"""
Special methods for the double integral on symmetric matrix with singularity on diagonal entries.
Expand Down
130 changes: 65 additions & 65 deletions src/sampling.jl
Original file line number Diff line number Diff line change
@@ -1,65 +1,65 @@
"""
Monte-Carlo sampling of any objective function without storage in memory.
The function must return Tuple{Number,Number} or Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}
# Arguments
- `samplingfunction::Function`: The function to be sampled
- `M::Int`: Monte-Carlo sampling size
# Returns
- `Tuple{Number,Number}`: The mean and variance of the sampled function
- `Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}`: The mean and variance of the sampled function
# Example
```julia
f(x) = x^2
sampling(f, 1000)
```
# Reference
https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
"""
function serialsampling(samplingfunction::Function, M::Int)::Union{Tuple{Number,Number},Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}}
A = samplingfunction()
A isa Array ? A .= 0 : A = 0
Q = copy(A)
for k in 1:M
x = samplingfunction()::Union{Number,VecOrMat{<:Number}}
Q = Q + (k - 1) / k * abs.(x - A) .^ 2
A = A + (x - A) / k
end
return A, Q / (M - 1)
end

"""
Multi-threaded Monte-Carlo sampling of any objective function.
The function must return Tuple{Number,Number} or Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}
"""
function parallelsampling(samplingfunction::Function, M::Int)::Union{Tuple{Number,Number},Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}}
obj = samplingfunction()
if obj isa Number
cache = zeros(typeof(obj), M)
@threads for i in 1:M
cache[i] = samplingfunction()
end
A = mean(cache)
Q = var(cache)
return A, Q
elseif obj isa Vector
cache = zeros(typeof(obj).parameters[1], length(obj), M)
@threads for i in 1:M
cache[:, i] .= samplingfunction()
end
A = dropdims(mean(cache, dims=2),dims=2)
Q = dropdims(var(cache, dims=2),dims=2)
return A, Q
elseif obj isa Matrix
cache = zeros(typeof(obj).parameters[1], size(obj)..., M)
@threads for i in 1:M
cache[:, :, i] .= samplingfunction()
end
A = dropdims(mean(cache, dims=3),dims=3)
Q = dropdims(var(cache, dims=3),dims=3)
return A, Q
else
error("The objective function must return `VecOrMat{<:Number}` or `Number`")
end
end
"""
Monte-Carlo sampling of any objective function without storage in memory.
The function must return Tuple{Number,Number} or Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}
# Arguments
- `samplingfunction::Function`: The function to be sampled
- `M::Int`: Monte-Carlo sampling size
# Returns
- `Tuple{Number,Number}`: The mean and variance of the sampled function
- `Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}`: The mean and variance of the sampled function
# Example
```julia
f(x) = x^2
sampling(f, 1000)
```
# Reference
https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
"""
function serialsampling(samplingfunction::Function, M::Int)::Union{Tuple{Number,Number},Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}}
A = samplingfunction()
A isa Array ? A .= 0 : A = 0
Q = copy(A)
for k in 1:M
x = samplingfunction()::Union{Number,VecOrMat{<:Number}}
Q = Q + (k - 1) / k * abs.(x - A) .^ 2
A = A + (x - A) / k
end
return A, Q / (M - 1)
end

"""
Multi-threaded Monte-Carlo sampling of any objective function.
The function must return Tuple{Number,Number} or Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}
"""
function parallelsampling(samplingfunction::Function, M::Int)::Union{Tuple{Number,Number},Tuple{VecOrMat{<:Number},VecOrMat{<:Number}}}
obj = samplingfunction()
if obj isa Number
cache = zeros(typeof(obj), M)
@threads for i in 1:M
cache[i] = samplingfunction()
end
A = mean(cache)
Q = var(cache)
return A, Q
elseif obj isa Vector
cache = zeros(typeof(obj).parameters[1], length(obj), M)
@threads for i in 1:M
cache[:, i] .= samplingfunction()
end
A = dropdims(mean(cache, dims=2),dims=2)
Q = dropdims(var(cache, dims=2),dims=2)
return A, Q
elseif obj isa Matrix
cache = zeros(typeof(obj).parameters[1], size(obj)..., M)
@threads for i in 1:M
cache[:, :, i] .= samplingfunction()
end
A = dropdims(mean(cache, dims=3),dims=3)
Q = dropdims(var(cache, dims=3),dims=3)
return A, Q
else
error("The objective function must return `VecOrMat{<:Number}` or `Number`")
end
end
72 changes: 36 additions & 36 deletions test/benchmark.jl
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
using SpinShuttling
using Statistics
import SpinShuttling.sampling

T=4; L=10; σ = sqrt(2) / 20; M = Int(1e6); N=999; κₜ=1;κₓ=1;
B=OrnsteinUhlenbeckField(0,[κₜ,κₓ],σ)
model=OneSpinModel(T,L,N,B)

function f(model::ShuttlingModel, randseq::Vector{<:Real}; isarray::Bool=false)::Complex
return exp(im*sum(model.R(randseq)))
end

println("Benchmark parallel sampling:")
@time sampling(model, f, M, isparallel=true)

println("Benchmark fidelity:")
@time sampling(model, statefidelity, M, isparallel=true)


println("Benchmark sequential sampling:")
@time sampling(model, f, M, isparallel=false)

function f(model::ShuttlingModel)::Complex
return exp(im*sum(model.R()))
end

println(typeof(model.R.L))
A=model.R.L|>collect
sample=zeros(Complex{Float64},M)
randpool=randn(M,N)
println("Benchmark standard sampling:")
@time for i in 1:M
sample[i]=cos(sum(A*randpool[i,:]))
end

mean(sample),var(sample)
using SpinShuttling
using Statistics
import SpinShuttling.sampling

T=4; L=10; σ = sqrt(2) / 20; M = Int(1e6); N=999; κₜ=1;κₓ=1;
B=OrnsteinUhlenbeckField(0,[κₜ,κₓ],σ)
model=OneSpinModel(T,L,N,B)

function f(model::ShuttlingModel, randseq::Vector{<:Real}; isarray::Bool=false)::Complex
return exp(im*sum(model.R(randseq)))
end

println("Benchmark parallel sampling:")
@time sampling(model, f, M, isparallel=true)

println("Benchmark fidelity:")
@time sampling(model, statefidelity, M, isparallel=true)


println("Benchmark sequential sampling:")
@time sampling(model, f, M, isparallel=false)

function f(model::ShuttlingModel)::Complex
return exp(im*sum(model.R()))
end

println(typeof(model.R.L))
A=model.R.L|>collect
sample=zeros(Complex{Float64},M)
randpool=randn(M,N)
println("Benchmark standard sampling:")
@time for i in 1:M
sample[i]=cos(sum(A*randpool[i,:]))
end

mean(sample),var(sample)

0 comments on commit ee820b7

Please sign in to comment.