-
Notifications
You must be signed in to change notification settings - Fork 88
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
Add chebyshev Iteration #1289
base: develop
Are you sure you want to change the base?
Add chebyshev Iteration #1289
Conversation
Do you intend adding an eigenvalue estimation? I think that would be very helpful, because most times users don't have that available. I think PETSc is also doing that. I think this is the GMRES version used by PETSC to compute the estimate: https://petsc.org/release/docs/manualpages/KSP/KSPAGMRES/ |
@MarcelKoch thanks for providing these reference. I do not think I will put them in this pull request. From https://doi.org/10.1137/0907057, they introduce the algorithm From https://petsc.org/release/docs/manualpages/KSP/KSPCHEBYSHEV/#kspchebyshev, For GMRES, we need to get the Hessenberg out and compute eigenvalue on it. |
Kudos, SonarCloud Quality Gate passed! |
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.
Besides the comments left below, I want to mention the num_keep
and num_generated
mechanic. That needs some explaination, because right now I don't understand what that is for. It seems like some sort of restart mechanic, but I might be wrong there. Also, exposing this to the user seems confusing to me.
/** | ||
* The number of scalar to keep | ||
*/ | ||
int GKO_FACTORY_PARAMETER_SCALAR(num_keep, 2); |
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.
It is not clear what this parameter is for.
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.
Perhaps this means, construct Chebyshev polynomials until degree num_keep
, and after that just do IR with these polynomial?
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.
no, num_keep
is to keep the generated scalar in the storage.
alpha and beta are changed by iteration, but they are fixed by the given bound.
It's used for fixed iteration runs because we do not need to refill these scalars for different apply
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.
But shouldn't we then just keep all scalars?
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.
when using it as normal solver, we may not have the maximum iteration information.
allocating one big dense matrix and then moving them to another one when full may not be a good approach.
we can also add the ability of workspace such that it can handle the std::vector then it should be more flexible for uncertain size.
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 can not assume that there's an iteration criterion. It can contain the residual norm or time criterion.
If we assume that, we should provide the standalone iteration parameter.
Users do not need to know the implementation details.
The statement is to keep how many scalars for chebyshev to avoid the refill overhead.
I can introduce this usage later when we have the use case.
I think it should help the situation when kernel launch overhead is noticeable.
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.
You are right, this is very useful to negate the overhead. Still, I think we can assume that there is an iteration criterion somewhere in the combined one and use that. If not, we would just throw.
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.
You could set the default value to unspecified
, which you define before. When the solver is generated, you can check if the parameter is unspecified
and then try to extract an iteration criterion from the criteria. If that doesn't work, you throw with a message to either pass an iteration criterion or set this parameter to something else.
Or alternatively, just replace the criteria parameter with a iterations
parameter and move the class into the preconditioner namespace. I think that is also a fine option, since that would be the main use case anyway.
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 have moved it to based on the given iteration from stopping criterion.
It is only increased after creating object.
I also think whether staying a fixed number is enough or 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.
Thanks, I think it should be fine the way it is now.
/** | ||
* Chebyshev iteration is an iterative method that uses another coarse | ||
* method to approximate the error of the current solution via the current | ||
* residual. It has another term for the difference of solution. Moreover, this |
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.
* residual. It has another term for the difference of solution. Moreover, this | |
* residual. The solution is then updated using the Chebyshev polynomials. Moreover, this |
Is that what the sentence is trying to say? Anyway, I think it should be mentioned somewhere that this uses these polynomials.
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.
the solution x_i is also based on the
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.
TBH I don't see the relevance of that. Has that any effect for the user?
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.
no, I only try to explain the algorithm's difference from IR. IR uses
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 still think this has to be rephrased
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 try to rephrase it again. Could you take a look?
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 am fine with merging this PR when corrections in parts of the documentation that are pointed out (comments) take place. I could understand what num_keep variable was used for but perhaps a more descriptive name would be better.
c88ea63
to
f9d0e28
Compare
Kudos, SonarCloud Quality Gate passed! 0 Bugs 42.6% Coverage The version of Java (11.0.3) you have used to run this analysis is deprecated and we will stop accepting it soon. Please update to at least Java 17. |
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.
LGTM, but I would like to resolve some of my earlier issues. Other than that only minor nits.
/** | ||
* Chebyshev iteration is an iterative method that uses another coarse | ||
* method to approximate the error of the current solution via the current | ||
* residual. It has another term for the difference of solution. Moreover, this |
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 still think this has to be rephrased
Kudos, SonarCloud Quality Gate passed! 0 Bugs 59.4% Coverage The version of Java (11.0.3) you have used to run this analysis is deprecated and we will stop accepting it soon. Please update to at least Java 17. |
Quality Gate passedThe SonarCloud Quality Gate passed, but some issues were introduced. 27 New issues |
4d2ed80
to
15aeb09
Compare
24fc2df
to
6bc0ed5
Compare
Quality Gate passedIssues Measures |
Co-authored-by: Marcel Koch <[email protected]>
Co-authored-by: Marcel Koch <[email protected]>
Co-authored-by: Marcel Koch <[email protected]>
Co-authored-by: Marcel Koch <[email protected]>
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.
There are a few questions around data recycling and mutability I would like to discuss before merging this
* Chebyshev iteration is an iterative method that can solving nonsymeetric | ||
* problems. Chebyshev Iterations avoids the inner products for computation | ||
* which may be the bottleneck for distributed system. Chebyshev Iteration is | ||
* developed based on the Chebyshev polynomials of the first kind. Moreover, | ||
* this method requires knowledge about the spectrum of the preconditioned | ||
* matrix. This implementation follows the algorithm in "Templates for the | ||
* Solution of Linear Systems: Building Blocks for Iterative Methods, 2nd | ||
* Edition". |
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 would rearrange this slightly (the fact that we need to know the spectrum is important, so we should mention it early), and try to be consistent with capitalization of iteration.
* Chebyshev iteration is an iterative method that can solving nonsymeetric | |
* problems. Chebyshev Iterations avoids the inner products for computation | |
* which may be the bottleneck for distributed system. Chebyshev Iteration is | |
* developed based on the Chebyshev polynomials of the first kind. Moreover, | |
* this method requires knowledge about the spectrum of the preconditioned | |
* matrix. This implementation follows the algorithm in "Templates for the | |
* Solution of Linear Systems: Building Blocks for Iterative Methods, 2nd | |
* Edition". | |
* Chebyshev iteration is an iterative method for solving nonsymmeetric | |
* problems based on some knowledge of the spectrum of the (preconditioned) system matrix. It avoids the computation of inner products, | |
* which may be a performance bottleneck for distributed system. Chebyshev iteration is | |
* developed based on Chebyshev polynomials of the first kind. | |
* This implementation follows the algorithm in "Templates for the | |
* Solution of Linear Systems: Building Blocks for Iterative Methods, 2nd | |
* Edition". |
mutable size_type num_generated_scalar_ = 0; | ||
// num_max_generation_ is the number of generated scalar kept in the | ||
// workspace. | ||
mutable size_type num_max_generation_ = 3; |
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'm a bit wary of mutable members beyond well-controlled cases like the workspace. They might make future work on thread-safety more complicated. Not that I have a good alternative for it, but I want to bring it up.
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.
Isn't wokrspace handled in similar way?
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 don't have any mutability in our LinOps right now beyond vector caches and workspaces, most of the mutable
uses are in loggers etc. So the mutability is constrained into a single class. That's not the case here.
In general, if I write code, I expect a const
object to not change internally, and the only reasons we don't follow this requirement fully right now seems to be the need for cache data structures to avoid reallocation, and the fact that loggers are const
and can't change themselves without mutable
.
auto chebyshev_factory = | ||
gko::solver::Chebyshev<value_type>::build() | ||
.with_criteria( | ||
gko::stop::Iteration::build().with_max_iters(2u).on(ref)) |
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.
this entire file can use deferred factories
return SimpleSolverTest<gko::solver::Chebyshev<solver_value_type>>:: | ||
build(exec, iteration_count, check_residual) | ||
.with_preconditioner( | ||
precond_type::build().with_max_block_size(1u).on(exec)); |
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.
deferred?
|
||
|
||
namespace gko { | ||
namespace solver { |
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.
The naming solver is a bit of a stretch here - maybe even more so than IR. It makes sense for us that solvers are iterative algorithms that use a preconditioner, but from the user perspective, it's confusing. Maybe we need a concept in-between, like smoother
, but that could also include classical preconditioners like Gauß-Seidel
} | ||
|
||
|
||
TYPED_TEST(Chebyshev, SolvesTriangularSystemUsingAdvancedApplyMixed) |
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 this actually mixed precision? Doesn't look like it to me on a first glance
} | ||
|
||
|
||
TYPED_TEST(Chebyshev, SolvesTriangularSystemUsingAdvancedApplyMixedComplex) |
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 this mixed precision?
this->template log<log::Logger::iteration_complete>( | ||
this, dense_b, dense_x, iter, residual_ptr, nullptr, nullptr, | ||
solver, dense_b, dense_x, iter, residual_ptr, nullptr, nullptr, |
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.
Here solver == this
, so I would suggest removing the capture
auto old_num_max_generation = num_max_generation_; | ||
// Use the scalar first | ||
// get the iteration information from stopping criterion. | ||
visit_criteria( |
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 think this should be a separate parameter, not derived from the stopping criterion. The stopping criteria are not really intended to be queried this way.
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.
It was. but @MarcelKoch suggested that getting it from stopping criterion to reduce the parameter, I think.
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 we put it as a separate parameter, then we should not allow for a stopping criteria parameter. This would be fine with me, but I think it causes other issues, as this can't be considered a solver anymore.
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.
The smoother doesn't have much purpose with norm-based stopping criteria, because that would negate the benefit of avoiding reductions, right? And can it run correctly when it uses more iterations than the number of stored scalar values? If yes, then we could have two separate parameters iterations and subspace_dimension (or similar), if no, we could have just a single parameter iterations, and internally create an Iteration stopping criterion
if (num_generated_scalar_ < num_max_generation_) { | ||
alpha_scalar->fill(alpha_ref); | ||
// unused beta for first iteration, but fill zero | ||
beta_scalar->fill(zero<ValueType>()); | ||
num_generated_scalar_++; | ||
} |
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.
Am I understanding correctly that this us potentially re-using alpha and beta values from previous iterations? If so, that seems like it is using the workspace it was not originally intended for - it's intended for avoiding reallocation, not recycling values from previous iterations. That also relates to the mutable
members I would prefer to avoid.
@upsj To avoid the mutable and reusing value from workspace, I think moving them into generatio to pre-fill all alpha and beta before apply. I think it will also give better performance because we do not need to do some tiny fill before the limitation during apply. |
If those are just static coefficients independent of the matrix, that sounds very reasonable. I tend to agree with what I believe @MarcelKoch said, which is that we shouldn't consider changeable stopping criteria here. We also currently don't seem to have a way to propagate information from other parts of the solver hierarchy to compute appropriate focus values. |
It adds the Chebshev iteration in https://en.wikipedia.org/wiki/Chebyshev_iteration
The second-order richardson uses a similar formula but the scalars are constant in all iteration. Chebyshev Iteration update the scalar from the previous one (the scalar are the same if upper/lower eigval does not change)