动态定义函数

5
我正在测试Extreme Optimization C#库,具体是非线性系统求解器。 例如,我发现我必须将非线性系统以以下形式传递给求解器:
Func<Vector, double>[] f = {
  x => Math.Exp(x[0])*Math.Cos(x[1]) - x[0]*x[0] + x[1]*x[1],
  x => Math.Exp(x[0])*Math.Sin(x[1]) - 2*x[0]*x[1]
};

问题在于我试图解决的系统无法在设计时指定。它是由负荷流方程组成的非线性系统,用于解决交流电路的电路。这些方程由许多变量组成,这些变量取决于网格中节点的数量,该数量由用户指定。这些方程如下:

enter image description here

基本上每个节点有两个方程式,这是2*n个方程式,无法在单行中组成,因为它们依赖于i、j索引,因此我必须有2个嵌套的for循环来创建P和Q方程式。
有没有一种方法可以创建Func<Vector, double>[] f = {可变长度的方程系统};
我看到了帖子Creating a function dynamically at run-time,但它没有回答我的问题(我认为)
//************************EDIT**************************************
方程式的创建类似于以下内容:
For (int i=0; i< n; i++){
   double A=0.0;
   double B=0.0;
   For (int j=0; j< n; j++){
      A+= G[i,j]*Math.Cos(Theta[i,j]) + B[i,j]*Math.Sin(Theta[i,j])
      B+= G[i,j]*Math.Sin(Theta[i,j]) + B[i,j]*Math.Cos(Theta[i,j])
   }
   P[i]=V[i]*A;
   Q[i]=V[i]*B;
}

当然,A和B包含变量,而这个循环公式本身并没有太大意义。
提前感谢。

1
你能再给一些更改的例子吗?例如,展示一下你目前拥有的,比如你的两个嵌套的for循环... - Chris Moutray
是的,所以常量是G和B,变量可以是(V,theta)或(Q,theta),具体取决于节点类型,但为了简单起见,变量是V和Theta。如果我有3个节点,我将有6个方程式P1,Q1,P2,Q2,P3,Q3,其中有6个未知数(V1,theta1,V2,theta2,V3,theta3),但节点数量在运行时指定。 - Santi Peñate-Vera
你可能需要构建一个基本的DSL。 - Rezo Megrelidze
...你能否更新问题,包括你现有的代码中的2个嵌套for循环 - Chris Moutray
1个回答

2
您正在传递一个函数数组,所以做您想要的事情应该很容易:
Func<Vector, double>[] funcs = new Func<Vector, double>[howeverManyYouWant];

for (var i = 0; i < howeverManyYouWant; i++)
{
  var someConstant = 0.1f * i; // You need to define "constants" in scope

  funcs[i] = x => Math.Exp(x[0])*Math.Cos(x[1]) - x[0]*x[0] + x[1]*x[1];
}

您可以根据需要将该数组传递。如果无法提前确定数组的大小,则可以使用List<Func<Vector, double>>替代数组,然后在准备好时调用ToArray()。请注意,您实际上未传递Expression<Func<...>> - 这使一切变得更加简单,因为您可以在传递的函数内部使用for循环。
List<Func<Vector, double>> funcs 
  = new List<Func<Vector, double>>(howeverManyYouWant * 2);

for (var i = 0; i < howeverManyYouWant; i++)
{
  // P[i] equation
  funcs.Add
  (
    x => 
    {
      var a = 0d;

      for (var j = 0; j < howeverManyYouWant; j++)
      {
        a += G[i, j] * Math.Cos(Theta[i, j]) + B[i, j] * Math.Sin(Theta[i, j]);
      }

      return x[i] * a;
    }
  );

  // Add your Q[i] equation here the same way.
  funcs.Add(...);
}

您需要根据实际情况修改它,因为我不知道如何调用函数数组、传递给函数什么以及您想要作为常量或变量的内容等(在此示例中,我只是将V替换为x),但它确实展示了基本思路。
当然,您肯定希望在某个地方引用x,否则您显然可以预先计算该值,但那几乎没有什么帮助:)
考虑到这一点,我无法确定这是否符合您的要求。您需要指定哪些内容应被视为常量,哪些内容将传递给函数等。

Luaan,你如何定义求和函数?我对这种函数很陌生,不知道如何实现"For (int j=0; j< n; j++){...}"。 - Santi Peñate-Vera
@user3020849 这已经超出了原始问题的范围,但是...你实际上想做什么?你想解决什么问题?你期望什么输入和输出?至于求和,那非常棘手。首先,我会查看EO库 - 也许他们有一个针对他们使用优化的sum函数。如果没有,您还需要动态构建函数,这意味着手动调用各种Expression.Call等;然而,我担心这可能对EO处理速度过慢 - 您应该能够更好地近似解决方案。 - Luaan
问题被称为功率流,它使用牛顿-拉夫逊等方程组求解方法来解决(除其他方法外),当然没有简单的解决方法。http://en.wikipedia.org/wiki/Power-flow_study - Santi Peñate-Vera
@user3020849 是的,这就是我发现的。你希望EO库如何帮助你?它实际上能找到解决方案吗? - Luaan
方程的解决方案是知道电力系统的状态(每个节点的复杂功率和复杂电压),给定发电值和负载值。实际上,我的目标是包括方程和轮廓条件,以获得最佳值(优化),例如发电机的经济调度,最小损失等。 - Santi Peñate-Vera
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接