Гость
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Комбинация вариантов / 7 сообщений из 7, страница 1 из 1
29.05.2019, 15:55
    #39819907
BerlogaDen
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
Всем привет.

Помогите, пожалуйста, решить задачу.

Дан граф. (см рисунок в приложении). Из него нужно сделать 9 графов так, чтобы цветные вершины (не чёрные) не повторялись.

Изначально есть таблица с 11-ю строками, в которых хранится связь между вершинами (пара id). Одноцветные вершины символизируют группу замен, из которой нужно выбрать только одну вершину. Цифры возле ребёр - это типа приоритета в группе замены.

Есть ли готовое решение в PostgreSQL, которое могло бы выдаст желаемый результат - связи между вершинами в 9 графах?

Если нет, то помогите, пожалуйста с просчитыванием комбинаций.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
with tmp_a as (
	select t.* from (values (1, 4), (2, 5), (3, 7)) as t (_block, _var)
),
tmp_1 as (
	select b._val
	from (
		select generate_series(1,a._var) as _val
		from tmp_a a
		where a._block=1
		) b,
		(
		select generate_series(1,(select multiply(a._var) from tmp_a a where a._block<>1)::int) as _val
		) c
	order by c._val, b._val
),
tmp_2 as (
	select b._val
	from (
		select generate_series(1,a._var) as _val
		from tmp_a a
		where a._block=2
		) b,
		(
		select generate_series(1,(select multiply(a._var) from tmp_a a where a._block<>2)::int) as _val
		) c
	order by c._val, b._val
),
tmp_3 as (
	select b._val
	from (
		select generate_series(1,a._var) as _val
		from tmp_a a
		where a._block=3
		) b,
		(
		select generate_series(1,(select multiply(a._var) from tmp_a a where a._block<>3)::int) as _val
		) c
	order by c._val, b._val
)
select a._val as val_1, b._val as val_2, c._val as val_3, count(*)
from tmp_1 a, tmp_2 b, tmp_3 c
group by a._val, b._val, c._val
order by a._val, b._val, c._val


Вроде бы работает, но при увеличении вариантов в одной группе, то запрос начинает выполняться дольше. Хотелось бы вариант получше.
...
Рейтинг: 0 / 0
07.06.2019, 13:01
    #39823997
BerlogaDen
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
Может кто-то подскажет как можно ускорить следующий запрос (перебор комбинаций вариантов в матричном отображении)

Суть задачи. Дано N групп, в которых возможно M вариантов. В данном случае 4 группы, в каждой по 31 вариантов. Нужно сгенерировать таблицу комбинаций вариантов. Должно получится 923521 комбинаций (31*31*31*31), которые представлены как 3694084 записей (31*31*31*31*4) в результирующей таблице.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
explain analyze with tmp_1 as (
	select b._num, b.g_num, b.g_cnt, ((multiply(b.g_cnt) over (order by b.g_num))/b.g_cnt)::int as var_prev
	from (
		select row_number() over (order by t.g_num) as _num, t.* from (values (1,31), (2,31), (3,31), (4,31)) as t (g_num, g_cnt)
		) b
)
select d.v_num, d.g_num, 1 + d.val - e.g_cnt*div(d.val,e.g_cnt) as g_rank
from (
	select a.v_num, b.g_num, div(a.v_num-1,b.var_prev) as val
	from (
		select generate_series(1,multiply(c.g_cnt)::int) as v_num from tmp_1 c
		) a, tmp_1 b
	) d
	inner join tmp_1 e on d.g_num=e.g_num



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

Агрегатная функция multiply(numeric)
Код: plsql
1.
2.
3.
4.
CREATE AGGREGATE multiply(numeric) (
  SFUNC=numeric_mul,
  STYPE=numeric
);

...
Рейтинг: 0 / 0
08.06.2019, 20:40
    #39824494
ARTURV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
BerlogaDen,
Поиск в графе существенно зависит от решаемой задачи. Рекурсия не всегда работает быстро, хотя и выглядит элегантно.
Решаем задачу выхода из строя корабельных систем на основе графа связей оборудования, а далее оценку состояния корабельных функций
По существу Вам надо решить комбинаторную задачу для заполнения некоторой таблицы, из которой Вы будите быстро выбирать вариант. Совсем не обязательно реализовывать рекурсию.
Решение без рекурсии
Решалась задача:
Определить состояние функции корабля, состояние которой определяется состоянием комбинации корабельных систем влияющих на функцию.
Исходные данные:
1. Функции корабля
2. Таблица корабельных систем ship_system.ship_system
3. Таблица связи функции и системы ship_system.fighting_systems
Две функции для формирования вариантов.
Для оценки состояния функции необходим алгоритм состояния функции для каждого варианта

CREATE OR REPLACE FUNCTION var1(st integer)
RETURNS character varying AS
$BODY$
/* входной параметр - код функции корабля*/
BEGIN
-- добавить в таблицу варианты, где поражена только одна система из списка обеспечивающих функции корабля систем и сортируем по важности и номеру системы ---------------------------------
INSERT INTO var_syst_char
SELECT st,row_number() OVER ()::integer as cod,system_id,lev FROM (SELECT a.system_id,0 as lev,power FROM ship_system.fighting_systems a,
ship_system.ship_system b,ship_system.fighting_systems c where a.fighting_functions_id=st
and a.system_id=b.system_id and a.system_id=c.system_id and a.fighting_functions_id=c.fighting_functions_id
)as d ;
--Выполнить функцию var3 столько раз сколько систем обеспечивает функцию корабля - по существу это количество систем в комбинации, то есть ------------------------------------------
PERFORM var3(d::int ,st) FROM generate_series( 1 ,(SELECT count(system_id) FROM ship_system.fighting_systems where fighting_functions_id= st )) as d ;
------------------------------------------------------------------------------------------------------------------------------
RETURN '1';
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;
ALTER FUNCTION var1(integer)
OWNER TO postgres;

CREATE OR REPLACE FUNCTION var3(level integer)
RETURNS character varying AS
$BODY$
DECLARE
n_id integer;
c integer;
BEGIN
SELECT max(variant_id) into n_id FROM var_syst_char ; --получить максимальное значение варианта в таблице var_syst_char
INSERT INTO var_syst_char --добавить запись в таблицу var_syst_char
SELECT n_id +row_number() OVER ()::integer as cod,a.system_id||','||d.system_id,level FROM var_syst_char a,
--Выбрать коды боевых систем вариантов нулевого уровня, тоесть тех которые должны стоять в комбинаторном списке систем первыми --------------------------
(SELECT system_id FROM var_syst_char
where variant_id in (SELECT distinct variant_id FROM var_syst_char where lev=0 order by variant_id) --Выбрать список вариантов нулевого уровня
) as d
--------------------------------------------------------------------------------------------
where a.variant_id in (SELECT distinct variant_id FROM var_syst_char where lev=level-1 order by variant_id) --Выбрать список кодов вариантов уровня N
and not a.system_id=d.system_id --исключить совпадающие комбинации ----------------------
and not d.system_id<(SELECT b[level] from (SELECT (SELECT string_to_array(a.system_id,','))as b --исключит комбинации, которые меньше
) as f)
--(SELECT string_to_array(a.system_id,',')as a ) [level]
and position(d.system_id::varchar in a.system_id)=0
order by 1 ;
RETURN '1';
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;
ALTER FUNCTION var3(integer)
OWNER TO postgres;

Посмотрите, может, поможет
...
Рейтинг: 0 / 0
10.06.2019, 12:06
    #39824884
BerlogaDen
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
ARTURV, спасибо за помощь.

Но сколько аргументов у функции var3?
Код: plsql
1.
PERFORM var3(d::int ,st)


Вроде бы два.
Код: plsql
1.
2.
3.
4.
5.
CREATE OR REPLACE FUNCTION var3(level integer)
RETURNS character varying AS
$BODY$...$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;


А тут один.
...
Рейтинг: 0 / 0
13.06.2019, 21:38
    #39826340
ARTURV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
BerlogaDen,

Извините не заходил на форум. Было много работы

вы правы.У меня две функции и я скопировал не ту
CREATE OR REPLACE FUNCTION var3(
level integer,
str integer)
RETURNS character varying AS
$BODY$
DECLARE
n_id integer;
c integer;
BEGIN
SELECT max(variant_id) into n_id FROM var_syst_char where st=str ; --получить максимальное значение варианта в таблице var_syst_char
INSERT INTO var_syst_char --добавить запись в таблицу var_syst_char
SELECT str,n_id +row_number() OVER ()::integer as cod,a.system_id||','||d.system_id,level FROM var_syst_char a,
--Выбрать коды боевых систем вариантов нулевого уровня, тоесть тех которые должны стоять в комбинаторном списке систем первыми --------------------------
(SELECT system_id FROM var_syst_char
where variant_id in (SELECT distinct variant_id FROM var_syst_char where lev=0 AND st=str order by variant_id)AND st=str --Выбрать список вариантов нулевого уровня
) as d
--------------------------------------------------------------------------------------------
where a.variant_id in (SELECT distinct variant_id FROM var_syst_char where lev=level-1 AND st=str order by variant_id)AND st=str --Выбрать список кодов вариантов уровня N
and not a.system_id=d.system_id --исключить совпадающие комбинации ----------------------
and not d.system_id<(SELECT b[level] from (SELECT (SELECT string_to_array(a.system_id,','))as b --исключит комбинации, которые меньше
) as f)
--(SELECT string_to_array(a.system_id,',')as a ) [level]
and position(d.system_id::varchar in a.system_id)=0
order by 1 ;
RETURN '1';
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;
ALTER FUNCTION var3(integer, integer)
OWNER TO postgres;
...
Рейтинг: 0 / 0
17.06.2019, 12:45
    #39827183
BerlogaDen
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
ARTURVРекурсия не всегда работает быстро, хотя и выглядит элегантно
Я думал просчитаю все варианты заранее и сохраню результат. Вот я наивный.

Спасибо за помощь. Даже если просчитать все варианты, то результат (миллионы и миллионы строк) будет сохраняться в базе неоправданно долгое время. А нужные строки из этой большой кучи будут составлять мизерный процент. Лучше определить какой-нибудь критерий отбора как Вы и писали.
ARTURVПо существу Вам надо решить комбинаторную задачу
...
Рейтинг: 0 / 0
19.06.2019, 17:02
    #39828501
ARTURV
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Комбинация вариантов
BerlogaDen,
Нельзя сказать что формирование вариантов - это очень долго. Зато выборка быстро и подход инвариантен от "правил"
"Правила" (логика заданная постановщиком задачи) можно реализовать в виде процедуры, но Вам придется каждый раз переписывать обработку при изменении правил. Как реализовывать Ваш выбор.
Конечно расстановка "весов" вариантам выполняется процедурой в соответствии с заданными "правилами"
Я описал подход, который меня устраивает и не требует переписывания массы процедур оценки функционирования корабельных систем для разных проектов кораблей
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Комбинация вариантов / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]