У меня есть запрос на оптимизацию затрат, о котором я не знаю, если есть литература. Это немного сложно объяснить, поэтому заранее извиняюсь за длину вопроса.
Есть сервер, к которому я обращаюсь, который работает следующим образом:
- делается запрос по записям (r1, ...rn) и полям (f1, ...fp)
- вы можете запросить только декартово произведение (r1,...,rp) x (f1,...fp)
- Стоимость (время и деньги), связанные с таким запросом, аффинна размеру запроса:
T((r1, ..., rn)x(f1, ..., fp) = a + b * n * p
Без ограничения общности (просто путем нормализации) мы можем предположить, что b=1
стоимость равна:
T((r1, ...,rn)x(f1,...fp)) = a + n * p
- Мне нужно только запросить подмножество пар
(r1, f(r1)), ... (rk, f(rk))
, запрос, который исходит от пользователей. Моя программа действует как посредник между пользователем и сервером (который является внешним). У меня много таких запросов (десятки тысяч в день).
Графически мы можем думать об этом как о разреженной матрице n x p, для которой я хочу покрыть ненулевые значения прямоугольной подматрицей:
r1 r2 r3 ... rp ------ ___ f1 |x x| |x| f2 |x | --- ------ f3 .. ______ fn |x x| ------
Наличие:
- количество подматриц остается разумным из-за постоянной стоимости
- все «x» должны лежать в подматрице
- общая покрываемая площадь не должна быть слишком большой из-за линейных затрат
Я назову g коэффициентом разреженности моей задачи (количество необходимых пар от общего количества возможных пар, g = k / (n * p)
. Я знаю коэффициент a
.
Есть очевидные наблюдения:
- если a маленькое, лучшим решением будет запросить каждую пару (запись, поле) независимо, а общая стоимость составит:
k * (a + 1) = g * n * p * (a + 1)
- если a велико, лучшим решением будет запрос всего декартова произведения, а общая стоимость составит:
a + n * p
- второе решение лучше, как только
g > g_min = 1/ (a+1) * (1 + 1 / (n * p))
- конечно, порядки в декартовых произведениях не важны, поэтому я могу переставить строки и столбцы моей матрицы, чтобы ее было легче покрыть, например:
f1 f2 f3 r1 x x r2 x r3 x x
можно переупорядочить как
f1 f3 f2 r1 x x r3 x x r2 x
И есть оптимальное решение - запросить (f1,f3) x (r1,r3) + (f2) x (r2)
- Пробовать все решения и искать более низкую стоимость — не вариант, потому что комбинаторика взрывается:
for each permutation on rows: (n!) for each permutation on columns: (p!) for each possible covering of the n x p matrix: (time unknown, but large...) compute cost of the covering
поэтому ищу примерное решение. У меня уже есть какой-то жадный алгоритм, который находит покрытие по заданной матрице (он начинает с унитарных ячеек, затем объединяет их, если доля пустых ячеек в слиянии ниже некоторого порога).
Чтобы представить некоторые цифры, мое n находится где-то между 1 и 1000, а мое p где-то между 1 и 200. Шаблон покрытия действительно «блочный», потому что записи поступают в классы, для которых запрашиваемые поля похожи. К сожалению, я не могу получить доступ к классу записи...
Вопрос 1. Есть ли у кого-нибудь идея, умное упрощение или ссылка на статью, которая может оказаться полезной? Поскольку у меня много запросов, я ищу алгоритм, который в среднем работает хорошо (но я не могу позволить, чтобы он работал очень плохо в каком-то экстремальном случае, например, при запросе всего матрица, когда n и p велики, а запрос действительно довольно разреженный).
Вопрос 2. На самом деле проблема еще сложнее: стоимость на самом деле больше похожа на форму: a + n * (p^b) + c * n' * p'
, где b — константа ‹ 1 (как только запрашивается запись для поля, она не слишком дорого запрашивать другие поля), а n' * p' = n * p * (1 - g)
- это количество ячеек, которые я не хочу запрашивать (потому что они недействительны, а запрос недействительных вещей требует дополнительных затрат). Я даже не мечтаю о быстром решении этой проблемы, но все же... у кого есть идеи?