Альтернатива для рекурсивных агрегатных запросов, не поддерживаемых в sqlite3 - PullRequest
0 голосов
/ 26 марта 2019

Я хотел бы выполнить 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 невозможно пойти по этому пути.

Любая помощь будет высоко ценится. Спасибо!

...