-
Notifications
You must be signed in to change notification settings - Fork 72
Re-enable precompilation #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a6375b1
9ef79af
2933cef
1b7c3ea
d3efe79
f60412b
0444af6
5a9a878
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,19 +63,23 @@ _stridedordiag(A::Diagonal) = A | |
|
|
||
| Check that `C` has `numind(pC)` indices and that `pC` constitutes a valid permutation. | ||
| """ | ||
| function argcheck_index2tuple(C::AbstractArray, pC::Index2Tuple) | ||
| return ndims(C) == numind(pC) && isperm(linearize(pC)) || | ||
| argcheck_index2tuple(C::AbstractArray, pC::Index2Tuple) = argcheck_indextuple(C, linearize(pC)) | ||
| function argcheck_indextuple(C::AbstractArray, pC::IndexTuple) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if such functions need a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for the other
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is probably hard to reason about this, since the alternative is that the |
||
| ndims(C) == numind(pC) && isperm(pC) || | ||
| throw(IndexError(lazy"invalid permutation of length $(ndims(C)): $pC")) | ||
| return nothing | ||
| end | ||
|
|
||
| """ | ||
| argcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::Index2Tuple) | ||
|
|
||
| Check that `C` and `A` have `numind(pA)` indices and that `pA` constitutes a valid permutation. | ||
| """ | ||
| function argcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::Index2Tuple) | ||
| argcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::Index2Tuple) = | ||
| argcheck_tensoradd(C, A, linearize(pA)) | ||
| function argcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::IndexTuple) | ||
| ndims(C) == ndims(A) || throw(IndexError("non-matching number of dimensions")) | ||
| argcheck_index2tuple(A, pA) | ||
| argcheck_indextuple(A, pA) | ||
| return nothing | ||
| end | ||
|
|
||
|
|
@@ -85,14 +89,16 @@ end | |
| Check that the partial trace of `A` over indices `q` and with permutation of the remaining | ||
| indices `p` is compatible with output `C`. | ||
| """ | ||
| argcheck_tensortrace(C::AbstractArray, A::AbstractArray, p::Index2Tuple, q::Index2Tuple) = | ||
| argcheck_tensortrace(C, A, linearize(p), q) | ||
| function argcheck_tensortrace( | ||
| C::AbstractArray, A::AbstractArray, p::Index2Tuple, q::Index2Tuple | ||
| C::AbstractArray, A::AbstractArray, p::IndexTuple, q::Index2Tuple | ||
| ) | ||
| ndims(C) == numind(p) || | ||
| throw(IndexError(lazy"invalid selection of length $(ndims(C)): $p")) | ||
| 2 * numin(q) == 2 * numout(q) == ndims(A) - ndims(C) || | ||
| throw(IndexError("invalid number of trace dimensions")) | ||
| argcheck_index2tuple(A, ((p[1]..., q[1]...), (p[2]..., q[2]...))) | ||
| argcheck_indextuple(A, (p..., q[1]..., q[2]...)) | ||
| return nothing | ||
| end | ||
|
|
||
|
|
@@ -108,7 +114,15 @@ function argcheck_tensorcontract( | |
| B::AbstractArray, pB::Index2Tuple, | ||
| pAB::Index2Tuple | ||
| ) | ||
| argcheck_index2tuple(C, pAB) | ||
| return argcheck_tensorcontract(C, A, pA, B, pB, linearize(pAB)) | ||
| end | ||
| function argcheck_tensorcontract( | ||
| C::AbstractArray, | ||
| A::AbstractArray, pA::Index2Tuple, | ||
| B::AbstractArray, pB::Index2Tuple, | ||
| pAB::IndexTuple | ||
| ) | ||
| argcheck_indextuple(C, pAB) | ||
| argcheck_index2tuple(A, pA) | ||
| argcheck_index2tuple(B, pB) | ||
| numout(pA) + numin(pB) == ndims(C) || | ||
|
|
@@ -123,27 +137,28 @@ end | |
|
|
||
| Check that `C` and `A` have compatible sizes for the addition specified by `pA`. | ||
| """ | ||
| function dimcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::Index2Tuple) | ||
| dimcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::Index2Tuple) = dimcheck_tensoradd(C, A, linearize(pA)) | ||
| function dimcheck_tensoradd(C::AbstractArray, A::AbstractArray, pA::IndexTuple) | ||
| szA, szC = size(A), size(C) | ||
| TupleTools.getindices(szA, linearize(pA)) == szC || | ||
| TupleTools.getindices(szA, pA) == szC || | ||
| throw(DimensionMismatch("non-matching sizes in uncontracted dimensions")) | ||
| return nothing | ||
| end | ||
|
|
||
| """ | ||
| dimcheck_tensorcontract(C::AbstractArray, A::AbstractArray, | ||
| p::Index2Tuple, q::Index2Tuple) | ||
| dimcheck_tensorcontract(C::AbstractArray, A::AbstractArray, p::Index2Tuple, q::Index2Tuple) | ||
|
|
||
| Check that `C` and `A` have compatible sizes for the trace and addition specified by `p` and | ||
| `q`. | ||
| Check that `C` and `A` have compatible sizes for the trace and addition specified by `p` and `q`. | ||
| """ | ||
| dimcheck_tensortrace(C::AbstractArray, A::AbstractArray, p::Index2Tuple, q::Index2Tuple) = | ||
| dimcheck_tensortrace(C, A, linearize(p), q) | ||
| function dimcheck_tensortrace( | ||
| C::AbstractArray, A::AbstractArray, p::Index2Tuple, q::Index2Tuple | ||
| C::AbstractArray, A::AbstractArray, p::IndexTuple, q::Index2Tuple | ||
| ) | ||
| szA, szC = size(A), size(C) | ||
| TupleTools.getindices(szA, q[1]) == TupleTools.getindices(szA, q[2]) || | ||
| throw(DimensionMismatch("non-matching sizes in traced dimensions")) | ||
| TupleTools.getindices(szA, linearize(p)) == szC || | ||
| TupleTools.getindices(szA, p) == szC || | ||
| throw(DimensionMismatch("non-matching sizes in uncontracted dimensions")) | ||
| return nothing | ||
| end | ||
|
|
@@ -163,11 +178,19 @@ function dimcheck_tensorcontract( | |
| B::AbstractArray, pB::Index2Tuple, | ||
| pAB::Index2Tuple | ||
| ) | ||
| return dimcheck_tensorcontract(C, A, pA, B, pB, linearize(pAB)) | ||
| end | ||
| function dimcheck_tensorcontract( | ||
| C::AbstractArray, | ||
| A::AbstractArray, pA::Index2Tuple, | ||
| B::AbstractArray, pB::Index2Tuple, | ||
| pAB::IndexTuple | ||
| ) | ||
| szA, szB, szC = size(A), size(B), size(C) | ||
| TupleTools.getindices(szA, pA[2]) == TupleTools.getindices(szB, pB[1]) || | ||
| throw(DimensionMismatch("non-matching sizes in contracted dimensions")) | ||
| szAB = (TupleTools.getindices(szA, pA[1])..., TupleTools.getindices(szB, pB[2])...) | ||
| TupleTools.getindices(szAB, linearize(pAB)) == szC || | ||
| TupleTools.getindices(szAB, pAB) == szC || | ||
| throw(DimensionMismatch("non-matching sizes in uncontracted dimensions")) | ||
| return nothing | ||
| end | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,14 +6,13 @@ | |||||
| function blas_contract!(C, A, pA, B, pB, pAB, α, β, backend, allocator) | ||||||
| rpA = reverse(pA) | ||||||
| rpB = reverse(pB) | ||||||
| indCinoBA = let N₁ = numout(pA), N₂ = numin(pB) | ||||||
| map(n -> ifelse(n > N₁, n - N₁, n + N₂), linearize(pAB)) | ||||||
| # note: `pAB` is only ever consumed through `linearize`/`invperm` from here on, so it is | ||||||
| # canonicalized to an `IndexTuple` and the reversed permutation does not need to be | ||||||
| # repartitioned the way `pAB` is | ||||||
| pAB = linearize(pAB) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would have been nice to maybe also denote this one with a prime, i.e.
Suggested change
(Then also needs to be changed below) |
||||||
| rpAB = let N₁ = numout(pA), N₂ = numin(pB) | ||||||
| map(n -> ifelse(n > N₁, n - N₁, n + N₂), pAB) | ||||||
| end | ||||||
| tpAB = trivialpermutation(pAB) | ||||||
| rpAB = ( | ||||||
| TupleTools.getindices(indCinoBA, tpAB[1]), | ||||||
| TupleTools.getindices(indCinoBA, tpAB[2]), | ||||||
| ) | ||||||
| cp = allocator_checkpoint!(allocator) | ||||||
| if contract_memcost(C, A, pA, B, pB, pAB) <= contract_memcost(C, B, rpB, A, rpA, rpAB) | ||||||
| C = _blas_contract!(C, A, pA, B, pB, pAB, α, β, backend, allocator) | ||||||
|
|
@@ -28,15 +27,15 @@ function blas_contract!( | |||||
| C::StridedView{T, 2}, | ||||||
| A::StridedView{T, 2}, pA::Index2Tuple{1, 1}, | ||||||
| B::StridedView{T, 2}, pB::Index2Tuple{1, 1}, | ||||||
| pAB::Index2Tuple{1, 1}, | ||||||
| pAB::IndexTuple{2}, | ||||||
| α::Number, β::Number, | ||||||
| backend, allocator | ||||||
| ) where {T} | ||||||
| A′ = pA == ((1,), (2,)) ? A : transpose(A) | ||||||
| B′ = pB == ((1,), (2,)) ? B : transpose(B) | ||||||
| if pAB == ((1,), (2,)) | ||||||
| if pAB == (1, 2) | ||||||
| mul!(C, A′, B′, α, β) | ||||||
| elseif pAB == ((2,), (1,)) | ||||||
| elseif pAB == (2, 1) | ||||||
| mul!(C, transpose(B′), transpose(A′), α, β) | ||||||
| end | ||||||
| return C | ||||||
|
|
@@ -49,18 +48,23 @@ function _blas_contract!(C, A, pA, B, pB, pAB, α, β, backend, allocator) | |||||
| A_, pA, flagA = makeblascontractable(A, pA, TC, backend, allocator) | ||||||
| B_, pB, flagB = makeblascontractable(B, pB, TC, backend, allocator) | ||||||
|
|
||||||
| # the partition of `ipAB` is required by `isblasdestination` and `tensoralloc_add`, but | ||||||
| # the actual contraction only needs the linearized permutation | ||||||
| ipAB = oindABinC(pAB, pA, pB) | ||||||
| ipAB′ = linearize(ipAB) | ||||||
| flagC = isblasdestination(C, ipAB) | ||||||
| if flagC | ||||||
| C_ = C | ||||||
| _unsafe_blas_contract!(C_, A_, pA, B_, pB, ipAB, α, β) | ||||||
| _unsafe_blas_contract!(C_, A_, pA, B_, pB, ipAB′, α, β) | ||||||
| else | ||||||
| C_ = SV(tensoralloc_add(TC, C, ipAB, false, Val(true), allocator)) | ||||||
| _unsafe_blas_contract!( | ||||||
| C_, A_, pA, B_, pB, trivialpermutation(ipAB), | ||||||
| C_, A_, pA, B_, pB, trivialpermutation(ipAB′), | ||||||
| one(TC), zero(TC) | ||||||
| ) | ||||||
| tensoradd!(C, C_, pAB, false, α, β, backend, allocator) | ||||||
| # `C` already exists, so only the permutation of `pAB` matters here and it can be | ||||||
| # handed over in the canonical `{N,0}` partition | ||||||
| tensoradd!(C, C_, (pAB, ()), false, α, β, backend, allocator) | ||||||
| tensorfree!(C_.parent, allocator) | ||||||
| end | ||||||
| flagA || tensorfree!(A_.parent, allocator) | ||||||
|
|
@@ -74,7 +78,7 @@ function _unsafe_blas_contract!( | |||||
| C::StridedView{T}, | ||||||
| A::StridedView{T}, pA, | ||||||
| B::StridedView{T}, pB, | ||||||
| pAB, α, β | ||||||
| pAB::IndexTuple, α, β | ||||||
| ) where {T <: BlasFloat} | ||||||
| sizeA = size(A) | ||||||
| sizeB = size(B) | ||||||
|
|
@@ -84,7 +88,7 @@ function _unsafe_blas_contract!( | |||||
| osizeB = TupleTools.getindices(sizeB, pB[2]) | ||||||
|
|
||||||
| mul!( | ||||||
| sreshape(permutedims(C, linearize(pAB)), (prod(osizeA), prod(osizeB))), | ||||||
| sreshape(permutedims(C, pAB), (prod(osizeA), prod(osizeB))), | ||||||
| sreshape(permutedims(A, linearize(pA)), (prod(osizeA), prod(csizeA))), | ||||||
| sreshape(permutedims(B, linearize(pB)), (prod(csizeB), prod(osizeB))), | ||||||
| α, β | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to precompile for GPU arrays too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I understood yes and no, we can add a precompilation module to the package extensions to compile the "bookkeeping code", but from what I understood the actual GPU kernels themselves not yet (although it seemed like Tim was working on this). For cuTENSOR this is probably worth it anyways, as that library is compiled