Умножение матриц пакетным запросом

Функция для умножения матриц, заданных ТаблицамиЗначений. Все вычисления в одном пакетном запросе.

Разместите в теле модуля нижеприведенные функции.

Предварительно подготовьте две числовые мартрицы с типом значения ТаблицаЗначений  (условно А и В). Либо программно, либо на форме с помощью элементов управления ТабличноеПоле.  Имена колонок могут быть любыми. Размерности таблиц должны удовлетворять условию  А(n x m) , В(m x k).

Осуществите вызов функции ПроизведениеМатриц(А, Б).
В результате будет получена таблица произведения двух  матриц С(n x k). Результат можно загрузить в ТабличноеПоле, как и показано на рисунке.

 

Область практического применения может быть различной:
начиная от вспомогательного инструмента для обучения студентов, и кончая наглядными экономическими расчетами.

Функция ПодготовитьИсходнуюТаблицу(ТЗ, Литера)

ИсходнаяТ = ТЗ.Скопировать();
ш = 1;
Для каждого Колонка Из ИсходнаяТ.Колонки Цикл Колонка.Имя = "elem" + ш; ш = ш + 1; КонецЦикла;
ИсходнаяТ.Колонки.Добавить("i", Новый ОписаниеТипов("Число", , ,Новый КвалификаторыЧисла(12,0)));
ш = 1;
Для каждого Стр Из ИсходнаяТ Цикл Стр.i = ш; ш = ш + 1; КонецЦикла;

Возврат ИсходнаяТ

КонецФункции

Функция ПолучитьЗапросДекомпозиция(м, Литера)

ЗапросДекомпозиция = "//";
Для ш = 1 По м Цикл

ЗапросДекомпозиция = ЗапросДекомпозиция +  " Объединить все
|ВЫБРАТЬ Таб.i как i, "+ш+"  как j, Таб.elem"+ш+" как elem
|"+?(ш=1, "Поместить Таб", "")+"
| ИЗ Исходная"+Литера+" КАК Таб
|";

КонецЦикла;

ЗапросДекомпозиция = СтрЗаменить(ЗапросДекомпозиция, "Таб", "Таб"+Литера);
ЗапросДекомпозиция = СтрЗаменить(ЗапросДекомпозиция, "// Объединить все", "") +";";

Возврат ЗапросДекомпозиция

КонецФункции // ()

Функция ПолучитьЗапросКомпозиция(м)

ЗапросКомпозицияСоединения = ""; ЗапросКомпозицияПоля = ""; ЗапросКомпозиция = "";
ЗапросНумерацияСтрок = "Выбрать ИсходнаяА.i Поместить НумерацияСтрок Из ИсходнаяА как ИсходнаяА;";
Для ш = 1 По м Цикл
ЗапросКомпозицияПоля = ЗапросКомпозицияПоля + ", РезультатТаблица"+ш+".c  как c" +ш;
ЗапросКомпозицияСоединения = ЗапросКомпозицияСоединения +  "
|Левое Соединение РезультатТаблица как РезультатТаблица"+ш+"  По РезультатТаблица"+ш+".j = "+ш+" И РезультатТаблица"+ш+".i = НумерацияСтрок.i";
КонецЦикла;

ЗапросКомпозиция = " Выбрать " + ЗапросКомпозицияПоля+ " Из НумерацияСтрок Как НумерацияСтрок " + ЗапросКомпозицияСоединения;

Возврат ЗапросНумерацияСтрок + СтрЗаменить(ЗапросКомпозиция,"Выбрать ,", "Выбрать ")

КонецФункции // ()


Функция ПроизведениеМатриц(ТабА, ТабБ)

мА = ТабА.Колонки.Количество(); мБ = ТабБ.Колонки.Количество();

Если Не мА = ТабБ.Количество() Тогда
Сообщить("Неверные размерности матриц!", СтатусСообщения.Важное); Возврат Неопределено;
КонецЕсли;

Запрос = Новый Запрос;
ЗапросТекст =  //Исходные матрицы с колонкой с нумерацией строк
"ВЫБРАТЬ * ПОМЕСТИТЬ ИсходнаяА ИЗ &ТабА КАК ТабА; ВЫБРАТЬ * ПОМЕСТИТЬ ИсходнаяБ ИЗ &ТабБ КАК ТабБ;";
//Разбор матрицы
ЗапросТекст = ЗапросТекст + ПолучитьЗапросДекомпозиция(мА, "А") + ПолучитьЗапросДекомпозиция(мБ, "Б");
//Умножение
ЗапросТекст = ЗапросТекст +
"ВЫБРАТЬ ТабА.i КАК i, ТабБ.j КАК j, СУММА(ТабА.elem * ТабБ.elem) КАК c
|Поместить РезультатТаблица
|ИЗ ТабА КАК ТабА ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТабБ КАК ТабБ ПО ТабА.j = ТабБ.i
|СГРУППИРОВАТЬ ПО ТабА.i, ТабБ.j;  ";
//Сбор матрицы
Запрос.Текст = ЗапросТекст + ПолучитьЗапросКомпозиция(мБ);

Запрос.УстановитьПараметр("ТабА", ПодготовитьИсходнуюТаблицу(T1, "а"));
Запрос.УстановитьПараметр("ТабБ", ПодготовитьИсходнуюТаблицу(T2, "б"));

Возврат Запрос.Выполнить().Выгрузить();

КонецФункции // ()

 

На данный момент вопрос быстродействия не исследовался.

4 Comments

  1. ildarovich

    Качественное решение непростой задачи. Но я не совсем согласен с самой идеей использования таблиц значений для работы с матрицами. Таблица значений «заточены» под работу со строками-записями. И рано или поздно это даст о себе знать. В том числе и при вводе и выводе. Матрицы лучше хранить и обрабатывать в виде, получаемом в Вашем случае после функции «декомпозиции», убрав нулевые значения.

    Reply
  2. zaxarovsky

    (1) ildarovich, спасибо!

    Да, я понял, что хранить и обрабатывать так будет удобно. Тут как раз-таки проблемки с вводом-выводом имеются. А как иначе, если нужно допустим вручную вводить значения да еще чтобы это выглядело привычно?

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

    Reply
  3. Synoecium

    само умножение конечно выглядит элегантно)

    а вот по поводу ввода матрицы в запрос, советую использовать подготовленную на встроенном языке таблицу значений. Что-то вроде:

    Для Строка=0 По ИсходнаяТаблица.Количество() Цикл

    Для Столбец=0 По ИсходнаяТаблица.Колонки.Количество() Цикл

    новСтрока = ТаблицаЗапроса.Добавить();

    новСтрока.i = Строка;

    новСтрока.j = Столбец;

    новСтрока.Значение = ИсходнаяТаблица[i][j];

    КонецЦикла

    КонецЦикла

    а затем работать в запросе с «уплощенной» таблицей. На собственном опыте убедился что объединение большого количества подзапросов очень медленно работает. Например, в УПП, запрос к табличной части документа «Табель учета рабочего времени» работает в несколько раз медленнее (объединение 120 таблиц), чем запрос к подготовленной таблице значений.

    Reply
  4. zaxarovsky

    (3) Synoecium,

    Тут вроде это не особо критично, так как всего (м) таблиц объединяется.

    Хотя, в конкретных приложениях, может так и следует поступить. Спасибо!

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *