Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多项式求值的生成方法_C#_Linq_Math_Expression Trees_Algebra - Fatal编程技术网

C# 多项式求值的生成方法

C# 多项式求值的生成方法,c#,linq,math,expression-trees,algebra,C#,Linq,Math,Expression Trees,Algebra,我试图想出一种优雅的方法来处理生成的多项式。以下是我们将(专门)针对这个问题关注的情况: 阶数是生成n阶多项式的参数,其中n:=阶数+1 i是范围为0..n的整数参数 多项式在x_j处有零,其中j=1..n和j≠ i(此时应该很清楚StackOverflow需要一个新功能,或者它已经存在,但我不知道) 多项式在x_i处计算为1 因为这个特定的代码示例生成x_1。。x_n,我将解释如何在代码中找到它们。这些点的间距均匀,其中n=order+1 我生成一个Func来计算这个多项式 private s

我试图想出一种优雅的方法来处理生成的多项式。以下是我们将(专门)针对这个问题关注的情况:

  • 阶数是生成n阶多项式的参数,其中n:=阶数+1
  • i是范围为0..n的整数参数
  • 多项式在x_j处有零,其中j=1..n和j≠ i(此时应该很清楚StackOverflow需要一个新功能,或者它已经存在,但我不知道)
  • 多项式在x_i处计算为1
  • 因为这个特定的代码示例生成x_1。。x_n,我将解释如何在代码中找到它们。这些点的间距均匀,其中
    n=order+1

    我生成一个
    Func
    来计算这个多项式

    private static Func<double, double> GeneratePsi(double elementSize, int order, int i)
    {
        if (order < 1)
            throw new ArgumentOutOfRangeException("order", "order must be greater than 0.");
    
        if (i < 0)
            throw new ArgumentOutOfRangeException("i", "i cannot be less than zero.");
        if (i > order)
            throw new ArgumentException("i", "i cannot be greater than order");
    
        ParameterExpression xp = Expression.Parameter(typeof(double), "x");
    
        // generate the terms of the factored polynomial in form (x_j - x)
        List<Expression> factors = new List<Expression>();
        for (int j = 0; j <= order; j++)
        {
            if (j == i)
                continue;
    
            double p = j * elementSize / order;
            factors.Add(Expression.Subtract(Expression.Constant(p), xp));
        }
    
        // evaluate the result at the point x_i to get scaleInv=1.0/scale.
        double xi = i * elementSize / order;
        double scaleInv = Enumerable.Range(0, order + 1).Aggregate(0.0, (product, j) => product * (j == i ? 1.0 : (j * elementSize / order - xi)));
    
        /* generate an expression to evaluate
         *   (x_0 - x) * (x_1 - x) .. (x_n - x) / (x_i - x)
         * obviously the term (x_i - x) is cancelled in this result, but included here to make the result clear
         */
        Expression expr = factors.Skip(1).Aggregate(factors[0], Expression.Multiply);
        // multiplying by scale forces the condition f(x_i)=1
        expr = Expression.Multiply(Expression.Constant(1.0 / scaleInv), expr);
    
        Expression<Func<double, double>> lambdaMethod = Expression.Lambda<Func<double, double>>(expr, xp);
        return lambdaMethod.Compile();
    }
    
    private static Func generatePI(双元素大小,整数顺序,整数i)
    {
    如果(顺序<1)
    抛出新ArgumentOutOfRangeException(“order”,“order必须大于0”);
    if(i<0)
    抛出新ArgumentOutOfRangeException(“i”,“i不能小于零”);
    如果(i>顺序)
    抛出新的ArgumentException(“i”,“i不能大于顺序”);
    ParameterExpression xp=Expression.Parameter(typeof(double),“x”);
    //生成形式为(x_j-x)的带因数多项式的项
    列表因子=新列表();
    对于(int j=0;j乘积*(j==i?1.0:(j*元素大小/顺序-xi));
    /*生成要计算的表达式
    *(x_0-x)*(x_1-x)…(x_n-x)/(x_i-x)
    *显然,在这个结果中(x_i-x)项被取消了,但在这里包含它是为了让结果更清楚
    */
    表达式expr=factors.Skip(1).聚合(factors[0],表达式.Multiply);
    //用比例乘以条件f(x_i)=1
    expr=Expression.Multiply(Expression.Constant(1.0/scaleInv),expr);
    表达式lambdaMethod=Expression.Lambda(expr,xp);
    返回lambdaMethod.Compile();
    }
    
    问题:我还需要计算ψ′=dψ/dx。为此,我可以将ψ=标度×(x_0-x)(x_1-x)×…(x_n-x)/(x_I-x)改写为ψ=α_n×x^n+α_n×x^(n-1)+α1×x+α0。这就给出了ψ′=n×αn×x^(n-1)+(n-1)×αn×x^(n-2)+1×α1

    出于计算原因,我们可以通过编写ψ′=x×(x×(x×(..)-β2)-β1)-β0重写最终答案,而无需调用
    Math.Pow

    要完成所有这些“诡计”(都是非常基本的代数),我需要一种干净的方法:

  • 展开包含
    ConstantExpression
    ParameterExpression
    的带系数的
    表达式
    叶和基本数学运算(最后是
    BinaryExpression
    并将
    节点类型设置为该运算)-这里的结果可以包括
    InvocationExpression
    元素到
    MethodInfo
    Math.Pow
    ,我们将始终以特殊方式处理这些元素
  • 然后我对一些指定的
    参数expression
    求导数。调用
    Math.Pow
    的右侧参数为常数2时,结果中的术语将替换为
    ConstantExpression(2)
    乘以左侧的值(调用
    Math.Pow(x,1)
    )。结果中的项由于相对于x为常数而变为零,将被删除
  • 然后计算出一些特定
    参数expression
    的实例,它们作为调用
    Math.Pow
    的左侧参数出现。当调用的右侧变成值为
    1
    ConstantExpression
    时,我们仅用
    参数表达式本身替换调用
  • 未来,我希望该方法采用
    参数表达式
    并返回一个基于该参数计算的
    表达式
    。这样我就可以聚合生成的函数。我还没到那里。
    ²将来,我希望发布一个通用库,将LINQ表达式用作符号数学。

    我使用.NET 4中的类型编写了一些符号数学功能的基础知识。它并不完美,但它看起来是一个可行的解决方案的基础。
    • Symbolic
      是一个公开方法的公共静态类,如
      Expand
      Simplify
      PartialDerivative
    • ExpandVisitor
      是一种内部帮助器类型,用于扩展表达式
    • SimplifyVisitor
      是一种简化表达式的内部帮助器类型
    • DerivativeVisitor
      是一种内部帮助器类型,它接受表达式的导数
    • ListPrintVisitor
      是一种内部帮助器类型,它将
      表达式
      转换为带有Lisp语法的前缀表示法
    Symbolic
    使用
    ExpandVisitor
    使用
    SimplifyVisitor
    使用
    ListPrintVisitor
    测试结果
    +因为在5行之后失去了我。。。这一定是个聪明的问题;)一、 另一方面,理解所有的数学知识,对LINQ一无所知!不过,看起来你的算法已经基本解决了。祝你在图书馆里好运@Jefromi:我可以很好地生成表达式树。我想要建立的是一种优雅的方式来变换这些树,将它们视为符号数学的表达式。:)是的,我理解这一点——也许我应该说我从未用表达式树实现过任何东西,而不是说我不认识LINQ。
    public static class Symbolic
    {
        public static Expression Expand(Expression expression)
        {
            return new ExpandVisitor().Visit(expression);
        }
    
        public static Expression Simplify(Expression expression)
        {
            return new SimplifyVisitor().Visit(expression);
        }
    
        public static Expression PartialDerivative(Expression expression, ParameterExpression parameter)
        {
            bool totalDerivative = false;
            return new DerivativeVisitor(parameter, totalDerivative).Visit(expression);
        }
    
        public static string ToString(Expression expression)
        {
            ConstantExpression result = (ConstantExpression)new ListPrintVisitor().Visit(expression);
            return result.Value.ToString();
        }
    }
    
    internal class ExpandVisitor : ExpressionVisitor
    {
        protected override Expression VisitBinary(BinaryExpression node)
        {
            var left = Visit(node.Left);
            var right = Visit(node.Right);
    
            if (node.NodeType == ExpressionType.Multiply)
            {
                Expression[] leftNodes = GetAddedNodes(left).ToArray();
                Expression[] rightNodes = GetAddedNodes(right).ToArray();
                var result =
                    leftNodes
                    .SelectMany(x => rightNodes.Select(y => Expression.Multiply(x, y)))
                    .Aggregate((sum, term) => Expression.Add(sum, term));
    
                return result;
            }
    
            if (node.Left == left && node.Right == right)
                return node;
    
            return Expression.MakeBinary(node.NodeType, left, right, node.IsLiftedToNull, node.Method, node.Conversion);
        }
    
        /// <summary>
        /// Treats the <paramref name="node"/> as the sum (or difference) of one or more child nodes and returns the
        /// the individual addends in the sum.
        /// </summary>
        private static IEnumerable<Expression> GetAddedNodes(Expression node)
        {
            BinaryExpression binary = node as BinaryExpression;
            if (binary != null)
            {
                switch (binary.NodeType)
                {
                case ExpressionType.Add:
                    foreach (var n in GetAddedNodes(binary.Left))
                        yield return n;
    
                    foreach (var n in GetAddedNodes(binary.Right))
                        yield return n;
    
                    yield break;
    
                case ExpressionType.Subtract:
                    foreach (var n in GetAddedNodes(binary.Left))
                        yield return n;
    
                    foreach (var n in GetAddedNodes(binary.Right))
                        yield return Expression.Negate(n);
    
                    yield break;
    
                default:
                    break;
                }
            }
    
            yield return node;
        }
    }
    
    internal class DerivativeVisitor : ExpressionVisitor
    {
        private ParameterExpression _parameter;
        private bool _totalDerivative;
    
        public DerivativeVisitor(ParameterExpression parameter, bool totalDerivative)
        {
            if (_totalDerivative)
                throw new NotImplementedException();
    
            _parameter = parameter;
            _totalDerivative = totalDerivative;
        }
    
        protected override Expression VisitBinary(BinaryExpression node)
        {
            switch (node.NodeType)
            {
            case ExpressionType.Add:
            case ExpressionType.Subtract:
                return Expression.MakeBinary(node.NodeType, Visit(node.Left), Visit(node.Right));
    
            case ExpressionType.Multiply:
                return Expression.Add(Expression.Multiply(node.Left, Visit(node.Right)), Expression.Multiply(Visit(node.Left), node.Right));
    
            case ExpressionType.Divide:
                return Expression.Divide(Expression.Subtract(Expression.Multiply(Visit(node.Left), node.Right), Expression.Multiply(node.Left, Visit(node.Right))), Expression.Power(node.Right, Expression.Constant(2)));
    
            case ExpressionType.Power:
                if (node.Right is ConstantExpression)
                {
                    return Expression.Multiply(node.Right, Expression.Multiply(Visit(node.Left), Expression.Subtract(node.Right, Expression.Constant(1))));
                }
                else if (node.Left is ConstantExpression)
                {
                    return Expression.Multiply(node, MathExpressions.Log(node.Left));
                }
                else
                {
                    return Expression.Multiply(node, Expression.Add(
                        Expression.Multiply(Visit(node.Left), Expression.Divide(node.Right, node.Left)),
                        Expression.Multiply(Visit(node.Right), MathExpressions.Log(node.Left))
                        ));
                }
    
            default:
                throw new NotImplementedException();
            }
        }
    
        protected override Expression VisitConstant(ConstantExpression node)
        {
            return MathExpressions.Zero;
        }
    
        protected override Expression VisitInvocation(InvocationExpression node)
        {
            MemberExpression memberExpression = node.Expression as MemberExpression;
            if (memberExpression != null)
            {
                var member = memberExpression.Member;
                if (member.DeclaringType != typeof(Math))
                    throw new NotImplementedException();
    
                switch (member.Name)
                {
                case "Log":
                    return Expression.Divide(Visit(node.Expression), node.Expression);
    
                case "Log10":
                    return Expression.Divide(Visit(node.Expression), Expression.Multiply(Expression.Constant(Math.Log(10)), node.Expression));
    
                case "Exp":
                case "Sin":
                case "Cos":
                default:
                    throw new NotImplementedException();
                }
            }
    
            throw new NotImplementedException();
        }
    
        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node == _parameter)
                return MathExpressions.One;
    
            return MathExpressions.Zero;
        }
    }
    
    internal class SimplifyVisitor : ExpressionVisitor
    {
        protected override Expression VisitBinary(BinaryExpression node)
        {
            var left = Visit(node.Left);
            var right = Visit(node.Right);
    
            ConstantExpression leftConstant = left as ConstantExpression;
            ConstantExpression rightConstant = right as ConstantExpression;
            if (leftConstant != null && rightConstant != null
                && (leftConstant.Value is double) && (rightConstant.Value is double))
            {
                double leftValue = (double)leftConstant.Value;
                double rightValue = (double)rightConstant.Value;
    
                switch (node.NodeType)
                {
                case ExpressionType.Add:
                    return Expression.Constant(leftValue + rightValue);
                case ExpressionType.Subtract:
                    return Expression.Constant(leftValue - rightValue);
                case ExpressionType.Multiply:
                    return Expression.Constant(leftValue * rightValue);
                case ExpressionType.Divide:
                    return Expression.Constant(leftValue / rightValue);
                default:
                    throw new NotImplementedException();
                }
            }
    
            switch (node.NodeType)
            {
            case ExpressionType.Add:
                if (IsZero(left))
                    return right;
                if (IsZero(right))
                    return left;
                break;
    
            case ExpressionType.Subtract:
                if (IsZero(left))
                    return Expression.Negate(right);
                if (IsZero(right))
                    return left;
                break;
    
            case ExpressionType.Multiply:
                if (IsZero(left) || IsZero(right))
                    return MathExpressions.Zero;
                if (IsOne(left))
                    return right;
                if (IsOne(right))
                    return left;
                break;
    
            case ExpressionType.Divide:
                if (IsZero(right))
                    throw new DivideByZeroException();
                if (IsZero(left))
                    return MathExpressions.Zero;
                if (IsOne(right))
                    return left;
                break;
    
            default:
                throw new NotImplementedException();
            }
    
            return Expression.MakeBinary(node.NodeType, left, right);
        }
    
        protected override Expression VisitUnary(UnaryExpression node)
        {
            var operand = Visit(node.Operand);
    
            ConstantExpression operandConstant = operand as ConstantExpression;
            if (operandConstant != null && (operandConstant.Value is double))
            {
                double operandValue = (double)operandConstant.Value;
    
                switch (node.NodeType)
                {
                case ExpressionType.Negate:
                    if (operandValue == 0.0)
                        return MathExpressions.Zero;
    
                    return Expression.Constant(-operandValue);
    
                default:
                    throw new NotImplementedException();
                }
            }
    
            switch (node.NodeType)
            {
            case ExpressionType.Negate:
                if (operand.NodeType == ExpressionType.Negate)
                {
                    return ((UnaryExpression)operand).Operand;
                }
    
                break;
    
            default:
                throw new NotImplementedException();
            }
    
            return Expression.MakeUnary(node.NodeType, operand, node.Type);
        }
    
        private static bool IsZero(Expression expression)
        {
            ConstantExpression constant = expression as ConstantExpression;
            if (constant != null)
            {
                if (constant.Value.Equals(0.0))
                    return true;
            }
    
            return false;
        }
    
        private static bool IsOne(Expression expression)
        {
            ConstantExpression constant = expression as ConstantExpression;
            if (constant != null)
            {
                if (constant.Value.Equals(1.0))
                    return true;
            }
    
            return false;
        }
    }
    
    internal class ListPrintVisitor : ExpressionVisitor
    {
        protected override Expression VisitBinary(BinaryExpression node)
        {
            string op = null;
    
            switch (node.NodeType)
            {
            case ExpressionType.Add:
                op = "+";
                break;
            case ExpressionType.Subtract:
                op = "-";
                break;
            case ExpressionType.Multiply:
                op = "*";
                break;
            case ExpressionType.Divide:
                op = "/";
                break;
            default:
                throw new NotImplementedException();
            }
    
            var left = Visit(node.Left);
            var right = Visit(node.Right);
            string result = string.Format("({0} {1} {2})", op, ((ConstantExpression)left).Value, ((ConstantExpression)right).Value);
            return Expression.Constant(result);
        }
    
        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (node.Value is string)
                return node;
    
            return Expression.Constant(node.Value.ToString());
        }
    
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return Expression.Constant(node.Name);
        }
    }
    
    [TestMethod]
    public void BasicSymbolicTest()
    {
        ParameterExpression x = Expression.Parameter(typeof(double), "x");
        Expression linear = Expression.Add(Expression.Constant(3.0), x);
        Assert.AreEqual("(+ 3 x)", Symbolic.ToString(linear));
    
        Expression quadratic = Expression.Multiply(linear, Expression.Add(Expression.Constant(2.0), x));
        Assert.AreEqual("(* (+ 3 x) (+ 2 x))", Symbolic.ToString(quadratic));
    
        Expression expanded = Symbolic.Expand(quadratic);
        Assert.AreEqual("(+ (+ (+ (* 3 2) (* 3 x)) (* x 2)) (* x x))", Symbolic.ToString(expanded));
        Assert.AreEqual("(+ (+ (+ 6 (* 3 x)) (* x 2)) (* x x))", Symbolic.ToString(Symbolic.Simplify(expanded)));
    
        Expression derivative = Symbolic.PartialDerivative(expanded, x);
        Assert.AreEqual("(+ (+ (+ (+ (* 3 0) (* 0 2)) (+ (* 3 1) (* 0 x))) (+ (* x 0) (* 1 2))) (+ (* x 1) (* 1 x)))", Symbolic.ToString(derivative));
    
        Expression simplified = Symbolic.Simplify(derivative);
        Assert.AreEqual("(+ 5 (+ x x))", Symbolic.ToString(simplified));
    }