Объединение делегатов в C# (алгоритм Sum-Product)
В настоящее время я реализую распространение убеждений для дискретных переменных.
Сообщения являются функциями. Мне нужно объединить их, используя продукты и суммы, для создания новых функций.
В настоящее время у меня есть базовая реализация с использованием делегатов, но я хочу знать, есть ли лучший способ справиться с этим. Я также обеспокоен тем, как это будет масштабироваться с использованием делегатов.
Вот пример моей реализации:
public Func<double, double> ProductFunc(List<Func<double, double>> messages)
{
// Construct the product of the message functions
Func<double, double> productFunc = delegate(double x)
{
double productValue = 1.0;
foreach(Func<double, double> message in messages)
{
productValue *= message(x);
}
return productValue;
};
return productFunc;
}
Есть ли более эффективный способ добиться этого?
1 ответ
Действительно ли код, который вы имеете, делает то, что вы хотите?
Я спрашиваю, потому что спецификация не очень понятна. Код, который вы имеете, фиксирует ссылку на List<Func<double, double>>
объект и возвращает Func<double, double>
делегат, который будет перечислять список в том виде, в котором он был в момент вызова делегата (в отличие от использования списка в тот момент, когда был вызван ваш метод).
Может быть, это действительно то, что вы хотите. Это согласуется с отложенным выполнением, которое используется, например, в LINQ. Но это означает, что вызывающая сторона должна либо предполагать, что изменения в списке изменят оценку возвращенного делегата, либо должна быть очень осторожна, чтобы не изменить список.
Если вместо этого вы пытаетесь захватить математические отношения, присутствующие во время вызова, вы можете предпочесть метод примерно так:
public Func<double, double> ProductFunc(List<Func<double, double>> messages)
{
Func<double, double> productFunc = x => 1.0;
foreach (Func<double, double> message in messages)
{
Func<double, double> currentFunc = productFunc;
productFunc = x => currentFunc(x) * message(x);
}
return productFunc;
}
Мне кажется, что в любом случае это хорошо. Это зависит только от того, какое поведение вы действительно хотите иметь в коде. В вашем вопросе недостаточно контекста, чтобы я это знал.
Я также обеспокоен тем, как это будет масштабироваться с использованием делегатов
Это должно масштабироваться просто отлично. Вы уже используете делегатов в любом случае. Составление их любым способом вряд ли вызовет чрезмерные проблемы с производительностью, и в любом случае код будет правильно выразительным как есть. Если вы столкнулись с конкретной проблемой производительности, так что код не удовлетворяет какой-либо объективной, измеримой цели производительности, тогда вы можете посмотреть, как настроить код для решения этой проблемы (и, вероятно, потерять хотя бы некоторую выразительность в процессе).