Генерация Случайных Не Сингулярных Целочисленных Матриц

в рамках алгоритма синтетического шума, я должен построить на лету много больших невырожденных квадратных матриц

a i, j (i, j: 1..n) / ∀ (i,j) a i, j ∈ ℤ и 0 ≤ a i, j ≤ k и Det[a] ≠ 0

но a i, j также должно быть случайным после равномерного распределения в [0, k].

в своем нынешнем воплощении проблема имеет n ≅ 300, k≅ 100.

In Mathematica, я могу генерировать матрицы случайных элементов очень быстро, но проблема в том, что я также должен проверить сингулярность. В настоящее время я использую для этого значение Determinant.

проблема в том, что эта проверка для матриц 300x300 занимает около 2 секунд, и я не могу себе этого позволить.

конечно, я могу построить строки, выбрав случайную первую строку, а затем построив последовательные ортогональные строки, но я не уверен, как гарантировать, что эти строки будут имеют свои элементы, следующие равномерному распределению в [0, k].

Я ищу решение в Mathematica, но также приветствуется более быстрый алгоритм генерации матриц.

NB> условие U[0,k] означает, что принято множество матриц, каждая позиция (i , j) по множеству должно следовать равномерное распределение.

4 ответов


если вы используете числовые приближенные матрицы в тестах сингулярности, вы получите гораздо лучшую скорость.

k = 100; n = 500;
mat = RandomInteger[100, {n, n}];

AbsoluteTiming[Det[mat] == 0]

Out[57]= {6.8640000, False}

AbsoluteTiming[Det[N@mat] == 0.] (*warning light!!*)

Out[58]= {0.0230000, False}

AbsoluteTiming[MatrixRank[N@mat] != n]

Out[59]= {0.1710000, False}

к сожалению, этот самый быстрый тест не является надежным. Но тест на звание должен работать хорошо. Вот краткий пример, в котором мы заменяем последнюю строку суммой предыдущих строк.

mat2 = mat;
mat2[[-1]] = Total[Most[mat]];

AbsoluteTiming[Det[mat2] == 0]

Out[70]= {9.4750000, True}

AbsoluteTiming[Det[N@mat2] == 0.]

Out[69]= {0.0470000, False}

AbsoluteTiming[MatrixRank[N@mat2] != n]

Out[71]= {0.1440000, True}

в принципе, я полагаю, что есть небольшой шанс, что тест ранга может дать ложное отрицание. скажем из-за плохого кондиционирования. Поскольку ваше использование будет лучше переносить ложные срабатывания (то есть неправильные утверждения о сингулярности), вы можете вместо этого проверить сингулярность по простому модулю. Я думаю, что это была одна из рекомендаций других сделанный.

продолжение приведенных выше примеров:

AbsoluteTiming[Det[mat, Modulus -> Prime[1000]]]

выход[77]= {0.6320000, 4054}

AbsoluteTiming[Det[mat2, Modulus -> Prime[1000]]]

выход[78]= {0.6470000, 0}

это медленно, но быстрее, чем более рациональных. Для чего это стоит, для большинства использования я был бы довольно уверен в результатах более быстрого тестирования через MatrixRank[N[matrix]].

Даниил Лихтблау Wolfram Research


как в Matlab, так и в Octave детерминант и Lu-факторизация матрицы 500x500 в основном мгновенны. У Mathematica есть режим, в котором он может вызвать LAPACK или какую-то подобную библиотеку? Возможно, вам придется отметить, что ваши массивы следует рассматривать как числа с плавающей запятой, а не символически; это может сделать это намного быстрее. Для сравнения, LU на матрице 5000x5000 занимает 8,66 секунды в моей системе с использованием Октавы; 500x500 должен быть примерно в 1000 раз быстрее чем.


можно использовать . На моей машине это примерно в n / 10 раз быстрее для больших целочисленных матриц nxn.


вот расширение комментария, который я сделал немного. Я согласен с Дэном, что очень маловероятно, что числовая версия вернет ложноположительный результат. Тем не менее, вы можете избежать этого сценария, изучив сингулярные значения и надежно вернув False, если наименьшее сингулярное значение больше некоторого допуска к ошибке. (По общему признанию, было бы немного сложно найти доказуемую терпимость.) Если наименьшее сингулярное значение неудобно мало, вы можете применить Det к целому числу матрица.

вот функция, которая должна быстро возвращать False для большинства неособых матриц. Если матрица близка к сингулярной, выполняется более дорогостоящее целочисленное вычисление.

singularQ[M_?MatrixQ] := If[
  Last[SingularValueList[N[M], Tolerance -> 0]] > 1/10.0^8,
 False, Det[M] == 0];

вот 200 матриц, которые соответствуют вашему описанию. Один в середине был сфальсифицирован как единственный.

SeedRandom[1];
matrices = RandomInteger[{0, 100}, {200, 300, 300}];
matrices[[100, -1]] = Sum[RandomInteger[{0, 10}]*matrices[[100, k]],
 {k, 1, Length[matrices[[100]]] - 1}];

Теперь давайте найдем индексы всех сингулярных матриц, наблюдая, как мы идем.

Flatten@Monitor[Table[
  If[singularQ[matrices[[k]]], k, {}],
  {k, 1, Length[matrices]}], k]