Ответ 1
@hpaulj комментарий о количестве ненулевых значений.
Когда вы вычисляете более высокие значения a
, количество ненулевых элементов
увеличивается. Для разреженных матриц время вычисления матрицы
произведение увеличивается с числом ненулевых элементов.
Алгоритм, используемый для вычисления a**16
, в действительности:
a2 = a*a
a4 = a2*a2
a8 = a4*a4
a16 = a8*a8
Теперь посмотрим на количество ненулевых элементов в этих матрицах
для a = sparse.rand(2049, 2049, 0.002)
:
matrix nnz fraction nnz
a 8396 0.0020
a2 34325 0.0082
a4 521593 0.1240
a8 4029741 0.9598
В последнем продукте a16 = a8*a8
коэффициенты 96% отличны от нуля. вычисления
этот продукт с использованием разреженного умножения матрицы медленный.
Этот последний шаг занимает 97% времени для вычисления a**16
.
С другой стороны, когда вы вычисляете a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
,
разреженное умножение матрицы выполняется 15 раз, но одно
факторов в каждом продукте всегда имеет небольшую долю (0,002)
ненулевых значений, поэтому каждый продукт может быть выполнен разумно
эффективно.
Это говорит о том, что существует, вероятно, оптимальная стратегия для вычисления продукта, балансируя количество умножений против разреженности факторов. Например, вычисление a2 = a*a; a16 = a2*a2*a2*a2*a2*a2*a2*a2
выполняется быстрее, чем a16 = a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
:
In [232]: %timeit a2 = a*a; a4 = a2*a2; a8 = a4*a4; a16 = a8*a8
14.4 s ± 199 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [233]: %timeit a16 = a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
1.77 s ± 4.78 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [234]: %timeit a2 = a*a; a16 = a2*a2*a2*a2*a2*a2*a2*a2
1.42 s ± 3.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Или, поскольку вы знаете, что конечный результат будет плотным, переключитесь на стандартные массивы numpy, начиная с начала или на каком-то промежуточном этапе, при котором плотное умножение матрицы будет более эффективным, чем разреженное умножение матрицы.