-
Notifications
You must be signed in to change notification settings - Fork 12
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
Clean up symmetrization and add optimization callback #62
Conversation
@lkdvos What do you think about the callback function in Also I didn't really spend time to rewrite the symmetrization, so I just refactored it a bit to make it more readable. It is definitely usable for now so I'd be fine with just merging it like this. I probably don't have the time currently to actually improve it and add the rotation symmetrization. |
Codecov ReportAttention: Patch coverage is
|
I think this all looks okay to me. I would call the As a side-note, I think we will have to reconsider our optimization interface again, the current approach has to many options, some of which are very non-obvious, and some are incompatible, so it is not that straightforward to get this going. This adds another option, which I think is fine, but we should probably think a bit about that at some point. Finally, @leburgel might not be too happy with the disappearance of |
I definitely agree. Currently, I'm using a wrapper struct around all the options which hides away some stuff and that makes launching optimizations definitely more usable. But on the other hand, PEPS optimizations just have a lot of parameter you have to be able to tweak in some way, so there should be a possibility to get fine-grained control over everything. Still, in its current form the interface is not super user-friendly. We should probably meet up at some point and discuss this in more detail, once we have the time.
I would also think that both scenarios are useful. There are probably cases where having either one or the other is fine. That should be a thing to think about when we come up with a new optimization interface at some point.
Haha, I just gave it a more descriptive name, the function is still there. (I do admit that it's quite useful sometimes :P) |
Looks like a strict improvement to me! Part of the motivation for calling it |
You definitely have a point. While it should be fine for now, it's good to keep in mind that we should revise that part of the code at some point :-)
That would be super nice and definitely a good thing to have in the future! By the way, I slightly changed the previous implementation of the finalize function such that it now uses that |
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.
If @leburgel is okay with the naming thing, you have my blessing. I left one remark in the code and have two more that I'll add here:
For the finalize!
kwarg, I am a bit torn between having that as a separate keyword, and having it part of the PEPSOptimize
alg. For consistency, it is nice that everything is in the algorithm struct, (and it might help with type stability issues), as I somehow like to have the following pattern:
run_algorithm(args...; kwargs...)
run_algorithm(args..., alg_struct) # expert mode
On the other hand, I might be okay with getting that fixed later, I really want to invest some time in getting a good grip on all the different kwargs with some good automated options there, so that could also just fit in that PR.
The second comment is about the j1j2 example as a test file. I think we could probably have either heisenberg or j1j2 as a test, and invest some time in getting a proper examples thing set up to add both. From a CI point of view, I don't think that testing both really makes that big of a difference, except increase the waiting times
test/ctmrg/symmetrization.jl
Outdated
function _test_elementwise_equal(peps1::InfinitePEPS, peps2::InfinitePEPS) | ||
return @test all(zip(peps1.A, peps2.A)) do (p1, p2) | ||
p1.data == p2.data | ||
end | ||
end |
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.
Do we want to just define ==
for pepses? I am also not entirely convinced that unpacking the tensor data is a solid approach, that really is reaching into the tensor internals which might break at some point.
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.
Yes, that's definitely the better way to do it. I now defined ==
and isapprox
methods for InfinitePEPS
which just use the TensorKit methods element-wise.
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.
On the other hand, I might be okay with getting that fixed later, I really want to invest some time in getting a good grip on all the different kwargs with some good automated options there, so that could also just fit in that PR.
Maybe I would suggest that we do it that way since it's not quite clear yet to me how to best automate all the options. Also, I'm always a bit hesitant to put functions into an algorithm struct since that makes it hard to save them to disk (which you probably want to do somewhere in the simulation workflow). So perhaps we can tackle that in a separate PR?
I think we could probably have either heisenberg or j1j2 as a test, and invest some time in getting a proper examples thing set up to add both. From a CI point of view, I don't think that testing both really makes that big of a difference, except increase the waiting times
Sounds like a good idea. But would you in general like to keep the square_lattice_heisenberg
and square_lattice_j1j2
functions separate? Technically, the Heisenberg model is just a special case of the J1-J2 model. However, I thought it would be useful to have both functions because with the Heisenberg one you can tweak
One reason to maybe keep both tests would be to check that the PEPS optimization runs fine for different parameter ranges of the same Hamiltonian (which is not always guaranteed I guess). If we decide to test only one of them it's probably best to test the J1-J2 model since that also includes next-nearest neighbor terms.
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.
I guess the bigger question is if the different parameter regimes would fail because of an implementation detail, or just because the algorithms are not suited. The CI really is just there to check that the code does what it is advertising, and it might be that the implementations are "perfect", and still the optimization does not converge.
If it does not take too long, it's completely fine to keep them in, but we should not be using the test-suite to explore too many models I guess. I like that J1J2 tests the next-nearest neighbor terms, so that actually increases "test coverage", but tweaking parameters does not :)
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.
left some final small comments, otherwise good to go for me
src/algorithms/peps_opt.jl
Outdated
g = only(g) # withgradient returns tuple of gradients `g` | ||
return E, g |
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.
g = only(g) # withgradient returns tuple of gradients `g` | |
return E, g | |
return E, only(g) # withgradient returns tuple of gradients `g` |
While it might be a little more readable, you should be careful with re-using the same variable name for things like this. Sometimes, the compiler gets confused and can no longer figure out the type of g
, especially in contexts like these with anonymous functions etc.
So I would either keep it as it was, or use E, gs
for the return values of withgradient
and then g = only(gs)
.
I don't have a preference about that :)
test/ctmrg/symmetrization.jl
Outdated
function PEPSKit._fit_spaces(data_peps::InfinitePEPS, space_peps::InfinitePEPS) | ||
fitted_tensors = map(zip(data_peps.A, space_peps.A)) do (pd, ps) | ||
PEPSKit._fit_spaces(pd, ps) | ||
end | ||
return InfinitePEPS(fitted_tensors) | ||
end |
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.
we can probably just define this in PEPSKit ? It feels a bit strange to overload a function within the tests
Thanks for the comments and also for completing the PR :-) I didn't manage to do it yesterday anymore (was on a super long night train right without wi-fi). |
This PR cleans up the symmetrization functionality a bit and adds a callback keyword argument for
fixedpoint
which allows to call a user-specified function after each optimization iteration. Also, I added the J1-J2 model Hamiltonian and a small test since I anyway had that code lying around.