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

Dealing with the (temporary) lack of constant computations in const generics #5

Open
rob-p opened this issue Apr 29, 2021 · 3 comments

Comments

@rob-p
Copy link
Contributor

rob-p commented Apr 29, 2021

So, it turns out that currently (as of rust v1.51) with MVP const generics, we are not allowed to do simple computations with generic parameters. For example, it would be desirable to have something like this to automatically compute the size of the storage array we want to use based on the value of K provided to the class. However, such a capability is gated behind a feature flag on the nightly branch of rustc. We should determine how we want to handle this from a design perspective. I see a few options:

  1. Go with > 1 const generic parameter, to avoid having to do const-generic arithmetic on the receiving end. Once that is available in stable, we can of course simplify the interface. This is a little bit onerous, since now we have to e.g. provide a helper (const) function or macro or some such so that the user doesn't have to think about the number of words that should be used for storage, which is, anyway, error prone.
  2. Throw caution to the wind and require nightly rustc with the feature gate to allow ourselves to do the arithmetic we want with const generic parameters.
  3. Some other and much more clever solution I've not yet considered.

I'd appreciate others' thoughts on this.

@natir
Copy link
Contributor

natir commented Apr 22, 2022

Hi every one.

I think we can use this issue as a traking issue for rust const generic evolution, official rust tracking issue.

Since rust 1.59 we can now set a default value for const generic type, so we can define default Kmer store 31 base on one u64, or just by default Kmer is store on one u64, K value can be let at user choice. I think it's match with more generic case but user still choose good value.
If we add default value we must add HUGE warning in documentation about default value limitation.

About @rob-p question I made some test with nightly build it's work but I think it's not a good idea to use it. I think it's not a good idea to switch to nightly because it would limit the usage of the crate. The default values are already a big step forward in terms of readability/usability of the API.

I think that the miraculous solution could be the use of macro to generate an automatic custom type for the user. Some thing like:

macro_rules! kmer_type {
    ($padding:ty, $k:item, $name:ident) => {
	pub type $name = Kmer<$padding, $k, word_for_k::<$padding, $k>()>;
    }
}

@rob-p
Copy link
Contributor Author

rob-p commented Apr 22, 2022

Thanks for the thoughts @natir!

I also agree that requiring nightly is not a good idea. I'd like to be able to use this crate on stable, and I think most users live there as well. I like your macro idea to easily create the relevant k-mer type.

The other big feature I'd like to figure out is how to specialize the reverse complement for the different configurations we offer. In particular, the hack that I have now only works when the underlying storage type is u64 and the k-mer size is < 33 (i.e. the array is an array of 1 u64). Certainly, we can use the same RC trick for storage of type u8,u16,u32 as well. Moreover, I imagine we can even generalize the fun bit twiddling algorithm to do faster word-level RC for larger k-mers (where the array size is > 1).

The question, of course, is how to specialize the implementation on the storage type P. Right now, as per the recommendation on reddit, I'm using a standard if call to specialize on the array size, and relying on monomorphization and the compiler to do the appropriate optimizations (which they appear to do). However, when we also need to specialize on the storage type, I am less sure how to do that — at least in a way that works on stable and doesn't resort to const generic specialization features that only exist on the nightly branch. Any thoughts on this?

@natir
Copy link
Contributor

natir commented Apr 22, 2022

For a real specialization it seems that we are in the same situation as for the constant generic (it may happen one day) track issue

I'm thinking if we want to have a Kmer type with optimization at compile in stable rust, the only solution we have left is the use of macro, or going work rust complier to finish this two features.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants