Skip to content
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

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open

Add chebyshev Iteration #1289

wants to merge 18 commits into from

Conversation

yhmtsai
Copy link
Member

@yhmtsai yhmtsai commented Feb 22, 2023

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)

@yhmtsai yhmtsai added the 1:ST:WIP This PR is a work in progress. Not ready for review. label Feb 22, 2023
@yhmtsai yhmtsai self-assigned this Feb 22, 2023
@ginkgo-bot ginkgo-bot added reg:build This is related to the build system. reg:testing This is related to testing. mod:core This is related to the core module. mod:reference This is related to the reference module. type:solver This is related to the solvers labels Feb 22, 2023
@MarcelKoch
Copy link
Member

MarcelKoch commented Mar 14, 2023

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 briefly searched for that and here are some references that might be interesting for that:

I think this is the GMRES version used by PETSC to compute the estimate: https://petsc.org/release/docs/manualpages/KSP/KSPAGMRES/

@yhmtsai
Copy link
Member Author

yhmtsai commented Mar 20, 2023

@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
adaptive chebyshev iteration
Perform m-step GMRES and use the information from the Hessenberg matrix to get the estimation of eigenvalue (I may be wrong),
and then perform https://link.springer.com/article/10.1007/BF01389971 to get the parameter for chebchev
Repeat these two steps until converge
This will be more like a standalone solver not a smoother for multigrid because it will require several steps on GMRES, which is too expensive IMO.
We can introduce by with_adaptive(GMRES LinOpFactory)

From https://petsc.org/release/docs/manualpages/KSP/KSPCHEBYSHEV/#kspchebyshev,
More precisely, https://petsc.org/release/docs/manualpages/KSP/KSPChebyshevEstEigSet/
They use Lanczo or GMRES to get the maximum estimation to decide the parameter by following
min-eig-boundary = a * min-eigest + b * max-eigest = 0.1 max-eigest (default), and
max-eig-boundary = c * min-eigest + d * max-eigest = 1.1 max-eigest (default)
(because min_eigest is usually inaccurate)
By this, user can use the information by GMRES and generate min/max eig boundary for Chebyshev, so we do not need additional parameter?
It only does once in generation, so this is more usable for Multigrid

For GMRES, we need to get the Hessenberg out and compute eigenvalue on it.
GMRES eigenvalue and Lanczo are related to #135

@yhmtsai yhmtsai added 1:ST:ready-for-review This PR is ready for review and removed 1:ST:WIP This PR is a work in progress. Not ready for review. labels Mar 21, 2023
@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 8 Code Smells

44.3% 44.3% Coverage
7.1% 7.1% Duplication

Copy link
Member

@MarcelKoch MarcelKoch left a 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.

Comment on lines 185 to 188
/**
* The number of scalar to keep
*/
int GKO_FACTORY_PARAMETER_SCALAR(num_keep, 2);
Copy link
Member

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.

Copy link
Member

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?

Copy link
Member Author

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

Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* 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.

Copy link
Member Author

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 $x_{i-1} - x_{i-2}$

Copy link
Member

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?

Copy link
Member Author

@yhmtsai yhmtsai Aug 7, 2023

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 $x += \alpha M^{-1}r$, but chebyshev uses $x += \alpha_i M^{-1} r + \beta_i (x_{i-1} - x_{i-2})$ $(x_{i-1} - x_{i-2})$ is the additional term against IR

Copy link
Member

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

Copy link
Member Author

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?

@upsj upsj requested a review from vasilisge0 April 6, 2023 15:51
Copy link
Contributor

@vasilisge0 vasilisge0 left a 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.

@yhmtsai yhmtsai force-pushed the cheb_iter branch 3 times, most recently from c88ea63 to f9d0e28 Compare August 8, 2023 10:06
@sonarqubecloud
Copy link

sonarqubecloud bot commented Aug 8, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 21 Code Smells

42.6% 42.6% Coverage
4.4% 4.4% Duplication

warning 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.
Read more here

Copy link
Member

@MarcelKoch MarcelKoch left a 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
Copy link
Member

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

@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot E 1 Security Hotspot
Code Smell A 27 Code Smells

59.4% 59.4% Coverage
5.2% 5.2% Duplication

warning 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.
Read more here

@yhmtsai yhmtsai force-pushed the cheb_iter branch 3 times, most recently from 3f588f5 to 77a3551 Compare January 7, 2025 07:36
@ginkgo-bot
Copy link
Member

Error: The following files need to be formatted:

core/config/config_helper.hpp
core/config/registry.cpp
core/config/solver_config.cpp
core/solver/ir.cpp
core/solver/update_residual.hpp
core/test/config/solver.cpp
core/test/solver/chebyshev.cpp
test/solver/solver.cpp
test/test_install/test_install.cpp

You can find a formatting patch under Artifacts here or run format! if you have write access to Ginkgo

@yhmtsai
Copy link
Member Author

yhmtsai commented Feb 13, 2025

@upsj I have changed it to accept the host scalar now, so we do not need to store them in advanced.
I think we can take a look how much difference between passing by device pointer or host value in the future.
do you think it will change a lot in this case?

@yhmtsai yhmtsai requested a review from upsj February 13, 2025 14:57
Copy link
Member

@upsj upsj left a comment

Choose a reason for hiding this comment

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

I mainly want to discuss the need for mixed precision instantiation here

namespace chebyshev {


template <typename ValueType, typename ScalarType>
Copy link
Member

Choose a reason for hiding this comment

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

Does this actually need a second precision, or can we always use the highest precision available? This is memory-bound after all.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have the same thought and thinking maybe we just use double or complex directly?

Copy link
Member

Choose a reason for hiding this comment

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

If there is a numerical benefit to using a higher-precision multiplication every time, I would go for it

Copy link
Member Author

Choose a reason for hiding this comment

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

after rethink about it, I do not have a good way to use double or complex double without any information from the vector or matrix. Maybe still keep the same way as how we handle IR/richardson now. also I need the ScalarType, which is the ValueType from Chebyshev class

Copy link
Member Author

Choose a reason for hiding this comment

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

currently keep the value type of class but change fosi, alpha, beta type to double/complex
when dpcpp only support float not double, it will cast to float/complex internally to keep the same interface among all backends

Co-authored-by: Tobias Ribizel <mail@ribizel.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1:ST:ready-for-review This PR is ready for review 1:ST:run-full-test mod:core This is related to the core module. mod:reference This is related to the reference module. reg:build This is related to the build system. reg:testing This is related to testing. type:solver This is related to the solvers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants