AlternateVector: convenient representation for vectors of the form:
[a,b,a,b,a,b...]
AlternatePaddedVector: convenient representation for vectors of the form:
[x,a,b,a,b,a,b...,y]
The module is standalone.
To build a AlternateVector one needs to provide:
the value for odd indices
the value for even indices
the length.
The various values must be of the same type and the length must be greater than one. The way to build an AlternateVector is the following:
using AlternateVectors
value_odd=0.2
value_even=2.3
length_av=7
x_av=AlternateVector(value_odd,value_even,length_av)
7-element AlternateVector{Float64}:
0.2
2.3
0.2
2.3
0.2
2.3
0.2
AlternatePaddedVector
To build a AlternatePaddedVector one needs to provide:
the initial value
the value for even indices
the value for odd indices
the final value
the length
The various values must be of the same type and the length must be greater than three. The way to build an AlternatePaddedVector is the following:
using AlternateVectors
initial_value=0.2
value_odd=-0.2
value_even=2.3
final_value=1.3
length_av=7
x_av=AlternatePaddedVector(initial_value,value_even,value_odd,final_value,length_av)
7-element AlternatePaddedVector{Float64}:
0.2
2.3
-0.2
2.3
-0.2
2.3
1.3
Operation on Alternate Vectors
The following applies:
AlternateVector/AlternatePaddedVector is closed under getindex for range of integers.
using AlternateVectors
apv=AlternatePaddedVector(0.2,-2.0,4.0,2.3,70)
z_small=apv[1:7:50]
z_small
8-element AlternatePaddedVector{Float64}:
0.2
-2.0
4.0
-2.0
4.0
-2.0
4.0
-2.0
Any scalar unary function applied directly to AlternateVectors/AlternatePaddedVector will produce an array of the same type.
using AlternateVectors
av=AlternateVector(0.2,-2.0,10)
z_sin=@. sin(av)
z_sin
10-element AlternateVector{Float64}:
0.19866933079506122
-0.9092974268256817
0.19866933079506122
-0.9092974268256817
0.19866933079506122
-0.9092974268256817
0.19866933079506122
-0.9092974268256817
0.19866933079506122
-0.9092974268256817
Operation between Alternate Vectors
The following applies:
Binary scalar functions between AlternateVector and AlternateVector will produce AlternateVector.
Binary scalar functions between AlternatePaddedVector and AlternatePaddedVector will produce AlternatePaddedVector.
Binary scalar functions between AlternatePaddedVector and AlternateVector will produce AlternatePaddedVector.
Binary scalar functions between AlternatePaddedVector/AlternateVector and any other type deriving from AbstractArray will produce an array of the other type.
using AlternateVectors
x=AlternateVector(0.2,2.3,10)
y=randn(10)
z=AlternatePaddedVector(0.2,-2.0,4.0,2.3,10)
@. sin(x)*y+z
10-element Vector{Float64}:
0.19888893604862723
-1.5733118717852563
4.279736164544295
-2.047749549765119
4.089784303301104
-1.9959892035016813
4.0333358435156965
-1.7851575575187602
4.063226722535128
1.5689732519190769
Simple multiplication
using AlternateVectors, BenchmarkTools
n=10_000
x=AlternateVector(0.2,2.3,n)
y=randn(n)
x_c=collect(x)
@btime @. $x*$y;
@btime @. $x_c*$y;
2.108 μs (3 allocations: 78.19 KiB)
2.845 μs (3 allocations: 78.19 KiB)
Flipping sign based on index and sum
using AlternateVectors, BenchmarkTools, LinearAlgebra
n=10_000
function f_std_scalar(f_x)
N=length(f_x)
sum_z=zero(eltype(f_x))
for i in 1:N
w=ifelse(isodd(i),1,-1)
sum_z+=@views @inbounds w*f_x[i]
end
return sum_z
end
function f_std_scalar_2(f_x)
N=length(f_x)
sum_z=zero(eltype(f_x))
for i in 1:N
if(isodd(i))
sum_z+=@views @inbounds f_x[i]
else
sum_z-=@views @inbounds f_x[i]
end
end
return sum_z
end
function f_std_vec(f_x)
N=length(f_x)
idx=1:N
W=@. ifelse(isodd(idx),1,-1)
return sum(W.*f_x)
end
function f_std_vec_linear_algebra(f_x)
N=length(f_x)
idx=1:N
W=@. ifelse(isodd(idx),1,-1)
return dot(W,f_x)
end
function f_apv(f_x)
N=length(f_x)
W=AlternateVector(1,-1,N)
return sum(W.*f_x)
end
x=randn(n)
f_x=@. sin(x)+x*cos(x)
@btime f_std_scalar($f_x);
@btime f_std_scalar_2($f_x);
@btime f_std_vec($f_x);
@btime f_std_vec_linear_algebra($f_x);
@btime f_apv($f_x);
9.267 μs (0 allocations: 0 bytes)
9.267 μs (0 allocations: 0 bytes)
5.827 μs (6 allocations: 156.38 KiB)
11.751 μs (2 allocations: 78.16 KiB)
3.460 μs (3 allocations: 78.19 KiB)
Simpson Integration
using AlternateVectors, BenchmarkTools,LinearAlgebra
n2=10_000
function f_simpson_std_scalar(f_x)
N=length(f_x)
sum_z=zero(eltype(f_x))
for i in 1:N
w=ifelse(i==1,1/3,ifelse(i==N,1/3,4/3))
sum_z+=@views @inbounds w*f_x[i]
end
return sum_z
end
function f_simpson_std_vec(f_x)
N=length(f_x)
idx=1:N
W=@. ifelse(idx==1,1/3,ifelse(idx==N,1/3,4/3))
return sum(W.*f_x)
end
function f_simpson_std_vec_linear_algebra(f_x)
N=length(f_x)
idx=1:N
W=@. ifelse(idx==1,1/3,ifelse(idx==N,1/3,4/3))
return dot(W,f_x)
end
function f_simpson_apv(f_x)
N=length(f_x)
W=AlternatePaddedVector(1/3,4/3,4/3,1/3,N)
return sum(W.*f_x)
end
function f_simpson_apv_linear_algebra(f_x)
N=length(f_x)
W=AlternatePaddedVector(1/3,4/3,4/3,1/3,N)
return dot(W,f_x)
end
x2=randn(n2)
f_x2=@. sin(x2)+x2*cos(x2)
@btime f_simpson_std_scalar($f_x2);
@btime f_simpson_std_vec($f_x2);
@btime f_simpson_std_vec_linear_algebra($f_x2);
@btime f_simpson_apv($f_x2);
@btime f_simpson_apv_linear_algebra($f_x2);
9.267 μs (0 allocations: 0 bytes)
5.631 μs (6 allocations: 156.38 KiB)
3.460 μs (3 allocations: 78.19 KiB)
3.924 μs (3 allocations: 78.19 KiB)
9.287 μs (0 allocations: 0 bytes)
To be noticed the performance improvements thanks to the usage of AlternatePaddedVector, and to be noticed that the first function proposed is not compatible with the CUDA.jl stack.