Использование структур в параметрических типах, а не только в примитивных типах

#parameters #julia #type-inference #arbitrary-precision

Вопрос:

Проблема возникла, когда я работал с Mods.jl. Этот пакет не поддерживает арифметику произвольной точности, поскольку в качестве параметров могут передаваться только примитивные типы, т.Е. Mod{17} Работает нормально, но Mod{big"17"} нет.

В связи с этим я решил реализовать что-то вроде BigMod с двумя BigInt полями

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

Затем мне пришлось решить систему линейных сравнений, и, хотя она работала довольно хорошо Mod{N} ( A b с некоторой дополнительной магией), она вообще не работала BigMod .

Причина заключалась в том, что LinearAlgebra пакет использует oneunit функцию для вывода типов, но нет способа определить oneunit(::Type{BigMod}) , потому что мы не знаем модуль в этом случае (но мы знаем это для Mod{N} ). Однако эта функция может быть определена для переменной типа BigMod , т.е. oneunit(x::BigMod) .

Эта проблема может быть решена с помощью Base.return_types inside of LinearAlgebra для вывода типа, однако она кажется нестабильной по типу, а также возвращает набор возможных возвращаемых типов.

Я вижу только три способа решить эту проблему:

  1. В один прекрасный день можно было бы использовать любые (по крайней мере, неизменяемые) типы в параметрах. В этом случае дополнительный код не требуется, оригинал должен быть достаточно общим, чтобы все работало хорошо.
  2. В один прекрасный день вывод типов будет улучшен настолько, что не нужны подобные клуджи typeof(oneunit(eltype(B)) / oneunit(eltype(F))) , можно просто сказать return_type(/, eltype.((B,F))) , что является гораздо более общим.
  3. Боритесь с болью и перепишите все необходимые вещи из LinearAlgebra специально для BigMod

Существуют ли какие-либо другие способы достижения цели и какой способ является лучшим?

Комментарии:

1. Если вы в конечном итоге переписываете материал, я бы посоветовал сохранять значения в полях вместо параметров типа, как BigMod вы опубликовали. Mod{N} Подход в Mods.jl работал нормально, потому Int64 что был разрешен и более чем достаточно велик для большинства случаев. Ждать, пока основной язык разрешит больше вещей в качестве параметров типа, нецелесообразно. В какой-то момент он был расширен с only Int и Bool до типов isbits, поэтому, должно быть, была какая-то неразрешимая причина, по которой они не расширили его дальше.

Ответ №1:

Параметрические типы могут содержать только isbits или Symbol . Следовательно, вы могли бы использовать очень простой в реализации, но чрезвычайно грязный и неэффективный обходной путь.

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

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

И теперь вы могли бы использовать его как:

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

Может быть , ваши большие доходы в конце концов не такие уж и большие, и вы могли бы подумать ? using BitIntegers Чем вы могли бы сделать что-то вроде:

 julia> MyBigMod{int1024"55555555555555555555555"}
MyBigMod{55555555555555555555555}
 

Комментарии:

1. Не знал, что BitIntegers ваш ответ все прояснил. Спасибо!!!