[WIP] Implicit derivatives for CTMRG - #413
Conversation
Codecov Report❌ Patch coverage is
... and 5 files with indirect coverage changes 🚀 New features to boost your workflow:
|
|
After the build completes, the updated documentation will be available here |
…icitGradient` is limited to `SimultaneousCTMRG{<:HalfInfiniteProjector}`
|
|
||
| # north edge renormalization | ||
| function contract_E´(Ud::RightProjector{S, 3}, EnVd::LeftProjector{S, 5}) where {S} | ||
| @tensor E´[-1 -2 -3; -4] := Ud[-1; 1 2 3] * EnVd[1 2 3 -2 -3; -4] |
There was a problem hiding this comment.
This looks slightly fishy for fermions, but I might also be wrong. For the CTMRG contractions, when we use U' and Vd', don't we use * instead of contractions?
There was a problem hiding this comment.
Yes, this definitely broken for fermions. But I think currently everything about the C4v case is broken for fermions. Currently we're not allowing anyone to run a leading_boundary for any Fermionic() braiding style by throwing an explicit argument error. So it's not possible to get here in the first place when optimizing a fermionic network.
I can put another check on the braiding style at the start of the generate_symmetric_characteristic_equation function if that's better.
| C´ = Ud * EwCEnVd | ||
| C´ = _project_hermitian(C´) # project output | ||
| λ_C = dot(C, C´) | ||
| F1 = C´ / λ_C - C |
There was a problem hiding this comment.
| F1 = C´ / λ_C - C | |
| F1 = add!!(C´, C, -1, inv(λ_C)) |
I'm not entirely sure, but we might have rules set up for this such that it remains AD-able
There was a problem hiding this comment.
same suggestion on the other parts in this function
There was a problem hiding this comment.
Well, it seems this tries to differentiate straight through LinearAlgebra.BLAS.axpby! and then crashes. I can see what I think are VectorInterface rules in TensorKitMooncakeExt, but it seems these just aren't there for ChainRules.
| copyto!(block(F, c), _fourthroot_pullback(b)) | ||
| end | ||
| return NoTangent(), P_t(_elementwise_mult(ΔC, F)) | ||
| end | ||
| return C, fourthroot_pullback | ||
| end | ||
| function _fourthroot_pullback(C::AbstractMatrix) | ||
| Fdata = similar(C) | ||
| for i in axes(Fdata, 1), j in axes(Fdata, 2) | ||
| # Taking the diagonal only is okay, when dA is diagonal anyway: Fdata[i, i] = 1 / (4 * conj(C[i, i]^3)) | ||
| # However, for Q-deformed CTMRG, we need the full version: | ||
| Fdata[i, j] = 1 / conj(C[i, i]^3 + C[i, i] * C[j, j]^2 + C[i, i]^2 * C[j, j] + C[j, j]^3) |
There was a problem hiding this comment.
I think here it might be worth it to be slightly more careful about the memory, since we're now allocating a block in _fourthroot_pullback to immediately copy into the destination of F, which is then copied again in elementwise_mult, and I guess this is not really that heavy of toll it still kind of adds up.
It also feels like there is probably a broadcasting way of writing this, which makes it GPU compatible as well as removing the intermediates, something like this might work? (untested)
Cd = diagview(C)
Ct = transpose(Cd)
@. F = ΔC / conj(Cd^3 + Cd * Ct^2 + Cd^2 * Ct + Ct^3)| env_fixed = fix_phases(env_conv, signs, corner_phases, edge_phases) | ||
|
|
||
| # NOTE: explicitly keeping corner non-diagonal and (possibly) complex, for use in the backwards pass | ||
| C, E = only(env_fixed.corners[NORTHWEST, :, :]), only(env_fixed.edges[NORTH, :, :]) |
There was a problem hiding this comment.
Is there a reason for doing the slicing with : and then immediately calling only? would env.corners[NORTHWEST, 1, 1] not give the same result?
There was a problem hiding this comment.
I just liked the fact that it would error if you accidentally put in an environment with a non-trivial unit cell, but I'm not sure if it's even possible that this wouldn't be caught before ending up here.
| _, ΔC, ΔE = c4v_env_vjp(Δenv) | ||
|
|
||
| # apply Hermitian projectors to edge and corner cotangents | ||
| ΔE = _project_hermitian(ΔE) |
There was a problem hiding this comment.
I think the hermitian projectors in the versions of TensorKit we are using now are correctly differentiable
There was a problem hiding this comment.
I can use the TensorKit projector for the corners, but not for the edges. For the latter it's a very shady definition of "Hermitian" which assumes additional trivial spaceflips and acts on a tensor map that is very much not square, but there's no real way around that I think.
pbrehmer
left a comment
There was a problem hiding this comment.
Looks really good to me! I would personally like to give SequentialCTMRG with implicit differentiation a try but we can of course also postpone this to a later PR.
|
|
||
| function _check_algorithm_combination(::SequentialCTMRG, ::ImplicitGradient) | ||
| msg = "The `:ImplicitGradient` algorithm is not yet compatible with the `SequentialCTMRG` algorithm; select \ | ||
| SimultaneousCTMRG instead to use :ImplicitGradient" |
There was a problem hiding this comment.
As you suggested, I think we could just try to return the SVD tensors in the ctmrg_iteration of SequentialCTMRG, right? I'm still not super sure if this will actually lead to an element-wise converged environment but I think it should.
There was a problem hiding this comment.
Okay I gave this a try and didn't manage to get it to work with ImplicitGradient. The characteristic equations are apparently not fulfilled which I somewhat suspected. On the other hand, SequentialCTMRG does seem to be compatible with FixedPointGradient. I guess now the question is if we still want SequentialCTMRG to return the SVD tensors and perhaps try to circumvent the problems by running one iteration of SimultaneousCTMRG.
Co-authored-by: Lukas Devos <ldevos98@gmail.com>
Co-authored-by: Lukas Devos <ldevos98@gmail.com>
Co-authored-by: Lukas Devos <ldevos98@gmail.com>
Co-authored-by: Lukas Devos <ldevos98@gmail.com>
Co-authored-by: Paul Brehmer <paul.brehmer@univie.ac.at>
…dPointDifferentiation`
Adds implicit gradients for CTMRG contractions.
Reference: https://arxiv.org/abs/2607.15030