Hello, so, I have been trying accelerating this function called overlap by using broadcasting and dot notation instead of unpacking matrices elements using for loops. However, I am getting different results when I do that. I would appreciate help if someone has an alternative for this acceleration or has any clue where my math is going wrong:
1. Auxiliary functions
** overlap_2() is the accelerated function; it uses normalization_2(). distance() and doublefactorial() are the same in both cases.
abstract type AbstractBasisSet end
struct GaussianBasisSet <: AbstractBasisSet
R
α::Matrix{Float64}
d::Matrix{Float64}
ℓ::Int
m::Int
n::Int
end
function doublefactorial(number)
fact = foldl(Base.:*, range(number, 1, step=-2))
return fact
end
function normalization_2(α, ℓ, m, n)
N = (4 .* α).^(ℓ + m + n)
N /=
doublefactorial(2 * ℓ - 1) * doublefactorial(2 * m - 1) * doublefactorial(2 * n - 1)
N .*= ((2 .* α) ./ π).^(3 / 2)
N = sqrt.(N)
return N
end
function distance(Rᵢ, Rⱼ)
d = (Rᵢ[1] - Rⱼ[1])^2 + (Rᵢ[2] - Rⱼ[2])^2 + (Rᵢ[3] - Rⱼ[3])^2
return d
end
function normalization(α, ℓ, m, n)
N = (4 * α)^(ℓ + m + n)
N /=
doublefactorial(2 * ℓ - 1) * doublefactorial(2 * m - 1) * doublefactorial(2 * n - 1)
N *= ((2 * α) / π)^(3 / 2)
N = sqrt(N)
return N
end
2. The overlap functions
function overlap(basis)
n = length(basis)
S = zeros(n, n)
for i in 1:n, j in 1:n
basisᵢ = basis[i]
basisⱼ = basis[j]
Rᵢ = basisᵢ.R
Rⱼ = basisⱼ.R
dist = distance(Rᵢ, Rⱼ)
m = length(basisᵢ.α)
p = length(basisⱼ.α)
for k in 1:m, l in 1:p
αᵢ = basisᵢ.α[k]
αⱼ = basisⱼ.α[l]
dᵢ = basisᵢ.d[k]
dⱼ = basisⱼ.d[l]
ℓᵢ, mᵢ, nᵢ = basisᵢ.ℓ, basisᵢ.m, basisᵢ.n
ℓⱼ, mⱼ, nⱼ = basisⱼ.ℓ, basisⱼ.m, basisⱼ.n
a = (
exp(-αᵢ * αⱼ * dist / (αᵢ + αⱼ)) *
normalization(αᵢ, ℓᵢ, mᵢ, nᵢ) *
normalization(αⱼ, ℓⱼ, mⱼ, nⱼ) *
dᵢ *
dⱼ )
println("$i, $j")
S[i, j] += (
exp(-αᵢ * αⱼ * dist / (αᵢ + αⱼ)) *
normalization(αᵢ, ℓᵢ, mᵢ, nᵢ) *
normalization(αⱼ, ℓⱼ, mⱼ, nⱼ) *
dᵢ *
dⱼ
)
end
end
return S
end
function overlap_2(basis)
n = length(basis)
S = zeros(n, n)
for i in 1:n, j in 1:n
basisᵢ = basis[i]
basisⱼ = basis[j]
Rᵢ = basisᵢ.R
Rⱼ = basisⱼ.R
dist = distance(Rᵢ, Rⱼ)
αᵢ = basisᵢ.α
αⱼ = basisⱼ.α
println("$i, $j")
dᵢ = basisᵢ.d
dⱼ = basisⱼ.d
ℓᵢ, mᵢ, nᵢ = basisᵢ.ℓ, basisᵢ.m, basisᵢ.n
ℓⱼ, mⱼ, nⱼ = basisⱼ.ℓ, basisⱼ.m, basisⱼ.n
a = exp.(-αᵢ .* αⱼ .* dist ./ (αᵢ .+ αⱼ)) .*
normalization_2(αᵢ, ℓᵢ, mᵢ, nᵢ) .*
normalization_2(αⱼ, ℓⱼ, mⱼ, nⱼ) .*
dᵢ .* dⱼ
println(a)
S[i, j] = sum(exp.(-αᵢ .* αⱼ .* dist ./ (αᵢ .+ αⱼ)) .* normalization_2(αᵢ, ℓᵢ, mᵢ, nᵢ) .* normalization_2(αⱼ, ℓⱼ, mⱼ, nⱼ) .* dᵢ .* dⱼ)
end
return S
end
Inputs
*** if you want to reproduce the calculations:
GaussianBasisSet[GaussianBasisSet([0.0 0.0 0.85], [3.425250914 0.6239137298 0.168855404], [0.1543289673 0.5353281423 0.4446345422], 0, 0, 0), GaussianBasisSet([0.0 0.0 -0.85], [207.015607 37.70815124 10.20529731], [0.1543289673 0.5353281423 0.4446345422], 0, 0, 0), GaussianBasisSet([0.0 0.0 -0.85], [8.24631512 1.916266291 0.6232292721], [-0.09996722919 0.3995128261 0.7001154689], 0, 0, 0), GaussianBasisSet([0.0 0.0 -0.85], [8.24631512 1.916266291 0.6232292721], [0.155916275 0.6076837186 0.3919573931], 1, 0, 0), GaussianBasisSet([0.0 0.0 -0.85], [8.24631512 1.916266291 0.6232292721], [0.155916275 0.6076837186 0.3919573931], 0, 1, 0), GaussianBasisSet([0.0 0.0 -0.85], [8.24631512 1.916266291 0.6232292721], [0.155916275 0.6076837186 0.3919573931], 0, 0, 1)]