Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SuiteSparse_jll = "bea87d4a-7f5b-5778-9afe-8cc45184846c"

[weakdeps]
AppleAccelerate = "13e28ba4-7ad8-5781-acae-3021b1ed3924"
Pardiso = "46dd5b70-b6fb-5a00-ae2d-e8fea33afaf2"

[extensions]
AppleAccelerateExt = "AppleAccelerate"
MKLPardisoExt = "Pardiso"

[compat]
AppleAccelerate = "^0.4"
DataStructures = "^0.19"
DocStringExtensions = "~0.8, ~0.9"
HDF5 = "0.17"
Expand Down
11 changes: 11 additions & 0 deletions docs/src/reference/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,14 @@ symbols are exported from `PowerNetworkMatrices`.
```@autodocs
Modules = [PowerNetworkMatrices.KLUWrapper]
```

## `AccelerateWrapper`

`PowerNetworkMatrices.AccelerateWrapper` is a thin, allocation-aware wrapper over Apple's
`libSparse.dylib` (provided by the system Accelerate framework) used internally for sparse
linear solves on macOS. Non-Apple builds load stub fallbacks that throw on use. None of
these symbols are exported from `PowerNetworkMatrices`.

```@autodocs
Modules = [PowerNetworkMatrices.AccelerateWrapper]
```
112 changes: 0 additions & 112 deletions ext/AppleAccelerateExt.jl

This file was deleted.

27 changes: 7 additions & 20 deletions ext/MKLPardisoExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,28 +171,15 @@ function PNM._calculate_LODF_matrix_MKLPardiso(
a::SparseArrays.SparseMatrixCSC{Int8, Int},
ptdf::Matrix{Float64},
)
# The demand matrix `diag(1 - PTDF·A[i,i])` is diagonal, so the
# "solve" is a row-wise element-wise division. The Pardiso path that
# used to factor it and back-solve via `_pardiso_sequential_LODF!` /
# `_pardiso_single_LODF!` is no longer needed for this stage.
linecount = size(ptdf, 2)
ptdf_denominator_t = a * ptdf
m_I = Int[]
m_V = Float64[]
for iline in 1:linecount
if (1.0 - ptdf_denominator_t[iline, iline]) < PNM.LODF_ENTRY_TOLERANCE
push!(m_I, iline)
push!(m_V, 1.0)
else
push!(m_I, iline)
push!(m_V, 1 - ptdf_denominator_t[iline, iline])
end
end
lodf_t = zeros(linecount, linecount)
A = SparseArrays.sparse(m_I, m_I, m_V)
if linecount > PNM.DEFAULT_LODF_CHUNK_SIZE
PNM._pardiso_sequential_LODF!(lodf_t, A, ptdf_denominator_t)
else
PNM._pardiso_single_LODF!(lodf_t, A, ptdf_denominator_t)
end
lodf_t[LinearAlgebra.diagind(lodf_t)] .= -1.0
return lodf_t
m_V = PNM._build_lodf_demand(ptdf_denominator_t, linecount)
PNM._apply_lodf_demand!(ptdf_denominator_t, m_V)
return ptdf_denominator_t
end

end # module
72 changes: 72 additions & 0 deletions src/AccelerateWrapper/AccelerateWrapper.jl
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused why we are wrapping this. KLU's internals weren't very thread-safe, which made it a clearer case until that can be fixed upstream, but I thought AppleAccelerate.jl was a bit better now?

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
AccelerateWrapper

A small, allocation-aware wrapper over Apple's `libSparse.dylib`
(`/System/Library/Frameworks/Accelerate.framework/.../libSparse.dylib`)
designed for the access patterns of `PowerNetworkMatrices`:

- Cache the symbolic and numeric factorizations of a symmetric sparse matrix
(LDLT by default) and reuse them across many solves.
- Refresh the numeric factor (`numeric_refactor!`) while keeping the symbolic
analysis, without re-allocating the structural arrays.
- Solve dense and **sparse** right-hand sides in place, with the sparse path
packing only non-empty RHS columns into a bounded scratch block.
- Compute `A·X` and `A·x` directly via libSparse's `SparseMultiply`.

This module is intentionally lighter than the upstream `AppleAccelerate.jl`
package: it owns no high-level Julia wrappers over libSparse, exposes the
symbolic/numeric split directly, binds only the entry points used by PNM,
and is compile-gated to macOS so non-Apple builds never codegen the
`@ccall` sites.
"""
module AccelerateWrapper

import SparseArrays
import SparseArrays: SparseMatrixCSC, getcolptr, rowvals, nonzeros, nzrange
import LinearAlgebra

export AAFactorCache,
aa_factorize,
symbolic_factor!,
numeric_refactor!,
full_factor!,
full_refactor!,
solve!,
solve_sparse!,
solve_sparse,
is_factored,
aa_spmm!,
aa_spmv!

@static if Sys.isapple()
include("libsparse_bindings.jl")
include("aa_cache.jl")
include("solve_dense.jl")
include("solve_sparse_rhs.jl")
include("spmm.jl")
else
# Stub layer. Non-Apple builds never bind libSparse symbols, never codegen
# the `@ccall` sites, and never instantiate `SparseOpaqueFactorization`.
# The whole submodule reduces to these short bodies on Linux/Windows.
struct AAFactorCache end

_unavailable() = error(
"AccelerateWrapper is macOS-only (Sys.isapple() returned false). " *
"Use the KLU backend on non-Apple platforms.",
)

AAFactorCache(args...; kwargs...) = _unavailable()
aa_factorize(args...; kwargs...) = _unavailable()
symbolic_factor!(args...) = _unavailable()
numeric_refactor!(args...) = _unavailable()
full_factor!(args...) = _unavailable()
full_refactor!(args...) = _unavailable()
solve!(args...) = _unavailable()
solve_sparse!(args...; kwargs...) = _unavailable()
solve_sparse(args...; kwargs...) = _unavailable()
is_factored(::AAFactorCache) = false
aa_spmm!(args...) = _unavailable()
aa_spmv!(args...) = _unavailable()
end

end # module
Loading
Loading