4

The problem arose while I was working with Mods.jl. This package does not support arbitrary-precision arithmetic because only primitive types can be passed as parameters, i.e. Mod{17} works fine, but Mod{big"17"} not.

Due to this I decided to implement something like BigMod with two BigInt fields

struct BigMod <: AbstractMod
    value::BigInt
    modulus::BigInt
end

Then I had to solve system of linear comparisons, and whilst it worked pretty good for Mod{N} (A \ b with some additional magic) it didn't worked for BigMod at all.

The reason was that LinearAlgebra package uses oneunit function to inference types, but there's no way to define oneunit(::Type{BigMod}), because we don't know modulus in this case (but we do know it for Mod{N}). However this function could be defined for variable of the type BigMod, i.e. oneunit(x::BigMod).

This problem can be solved using Base.return_types inside of LinearAlgebra for type inference, however it seems to be type unstable as well as it returns a collection of possible return types.

I can see only three ways to solve this:

  1. One day one could use any (at least immutable) types in parameters. In this case no additional code is required, original should be generic enough for everything to work well.
  2. One day type inference would be improved enough so that no kludges like typeof(oneunit(eltype(B)) / oneunit(eltype(F))) are needed, one can just say return_type(/, eltype.((B,F))) which is much more generic.
  3. Fight through the pain and rewrite all necessary things from LinearAlgebra specially for BigMod

Are there any other ways to reach the goal and what way is the best?

1
  • If you do end up rewriting stuff, I'd suggest keeping values in fields instead of type parameters, like the BigMod you posted. The Mod{N} approach in Mods.jl worked fine because Int64 was allowed and more than big enough for most cases. Waiting for the core language to allow more things as type parameters isn't practical. At some point it was expanded from only Int and Bool to isbits types, so there must've been some intractable reason they didn't expand it further. Commented Nov 6, 2021 at 3:46

1 Answer 1

3

The parametric types can only contain isbits or Symbols. Hence, you could use a very easy to implement, yet extremely dirty and inefficient workaround.

struct MyBigMod{S} <: AbstractMod
    value::BigInt
end

Base.oneunit(::MyBigMod{S}) where S = parse(BigInt, string(S))

And now you could use it as:

julia> oneunit(MyBigMod{Symbol("55555555555555555555555")}(big"222222"))
55555555555555555555555

Perhaps your big ints are not that big after all and you could consider using BitIntegers? Than you could do something like:

julia> MyBigMod{int1024"55555555555555555555555"}
MyBigMod{55555555555555555555555}
Sign up to request clarification or add additional context in comments.

1 Comment

Didn't know about BitIntegers your answer made all clear. Thanks!!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.