Я хотел бы выполнить SQL-вычисления системы, развивающейся во времени как
v <- v + a (*) v
, где v
- вектор N
компонентов (N >> 10
), a
- матрица N
-by- N
, довольно разреженная, (*)
обозначает умножение матриц и эволюцию рекурсивно вычисляется как последовательность временных шагов, причем каждый шаг использует предыдущее значение v
. a
изменяется со временем как внешний фактор, но для этого вопроса достаточно предположить, что a
является постоянным.
Я мог бы выполнить этот цикл рекурсии на императивном языке, но базовые данные были немного запутанными, и SQL был великолепен для нормализации. Было бы неплохо просто закончить работу на одном языке.
Я обнаружил, что умножение матриц в порядке. Рекурсия тоже хорошо, с sqlite 3.8. Но умножение матриц внутри рекурсивного цикла не представляется возможным. Вот мой прогресс (также на http://sqlfiddle.com/#!5/ed521/1):
-- Example vector v
DROP TABLE IF EXISTS coords;
CREATE TABLE coords( row INTEGER PRIMARY KEY, val FLOAT );
INSERT INTO coords
VALUES
(1, 0.0 ),
(2, 1.0 );
-- Example matrix a
DROP TABLE IF EXISTS matrix;
CREATE TABLE matrix( row INTEGER, col INTEGER, val FLOAT, PRIMARY KEY( row, col ) );
INSERT INTO matrix
VALUES
( 1, 1, 0.0 ),
( 1, 2, 0.03 ),
( 2, 1, -0.03 ),
( 2, 2, 0.0 );
-- The timestep equation can also be expressed: v <- ( I + a ) (*) v, where the
-- identity matrix I is first added to a.
UPDATE matrix
SET val = val + 1.0
WHERE row == col;
-- Matrix multiply to evaluate the first step.
SELECT a.row AS row, SUM( a.val*v.val ) AS val
FROM coords v
JOIN matrix a
ON a.col == v.row
GROUP BY a.row;
Вот здесь и возникает проблема. Я не вижу, как сделать умножение матрицы без
GROUP BY
(агрегация) операция, но Sqlite3 специально не разрешает агрегацию внутри цикла рекурсии:
-- Recursive matrix multiply to evaluate a sequences of steps.
WITH RECURSIVE trajectory( row, val ) AS
(
SELECT row, val
FROM coords
UNION ALL
SELECT a.row AS row, SUM( a.val*v.val ) AS val
FROM trajectory v -- recursive sequence of steps
--FROM coords v -- non-recursive first step only
JOIN matrix a
ON a.col == v.row
GROUP BY a.row
LIMIT 50
)
SELECT *
FROM trajectory;
Возвращает
Error: recursive aggregate queries not supported
Нет сомнений, что у дизайнеров была какая-то четкая причина исключать это! Я удивлен, что СОЕДИНЕНИЯ разрешены, но GROUP BYs не разрешены. Я не уверен, каковы мои альтернативы.
Я нашел несколько других рекурсивных примеров, но все они, похоже, имеют тщательно отобранные проблемы, для которых агрегация или самостоятельные объединения внутри цикла не требуются. В документах (https://www.sqlite.org/lang_with.html) пример запроса рекурсивно обходит дерево и выполняет avg()
на выходе. Это немного отличается: агрегация происходит вне цикла, а при обходе дерева используется JOIN
s, но агрегация внутри цикла рекурсии отсутствует. Эта проблема возникает только потому, что рекурсия не зависит от агрегации, как в этой проблеме.
Другой пример, генератор Фибоначчи - это пример линейной динамической системы N = 2
, но с N = 2
реализации могут просто жестко закодировать два значения и матрицу умножить непосредственно в запросе, поэтому агрегирование не SUM()
нужно. В общем, с N >> 10
невозможно пойти по этому пути.
Любая помощь будет высоко ценится. Спасибо!