多项式评估的生成方法

2024-03-13

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

  1. order是生成的参数n三阶多项式,其中 n:=order + 1。
  2. i是 0..n 范围内的整数参数
  3. 多项式在 x_j 处有零点,其中 j = 1..n 且 j ≠ i(此时应该很清楚 StackOverflow 需要一个新功能,或者它已经存在但我不知道)
  4. 多项式在 x_i 处的计算结果为 1。

由于这个特定的代码示例生成 x_1 .. x_n,我将解释如何在代码中找到它们。点间隔均匀x_j = j * elementSize / order分开,在哪里n = order + 1.

我生成一个Func<double, double>来评估这个多项式。

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();
}

问题:我还需要评估 ψ′=dψ/dx。为此,我可以将 ψ=scale×(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。

出于计算原因,我们可以重写最终答案,而无需调用Math.Pow写成 ψ′=x×(x×(x×(..) - β_2) - β_1) - β_0。

为了完成所有这些“技巧”(所有非常基本的代数),我需要一种干净的方法来:

  1. 展开因式分解Expression含有ConstantExpression and ParameterExpression叶子和基本数学运算(最终要么BinaryExpressionNodeType设置为操作) - 这里的结果可以包括InvocationExpression元素到MethodInfo for Math.Pow我们将在整个过程中以特殊方式处理。
  2. 然后我对某些指定的导数进行求导ParameterExpression。结果中的术语,其中调用的右侧参数Math.Pow常数 2 被替换为ConstantExpression(2)乘以左边的值(调用Math.Pow(x,1)已移除)。结果中因相对于 x 为常数而变为零的项将被删除。
  3. 然后分解出一些特定的实例ParameterExpression它们作为调用的左侧参数出现Math.Pow。当调用的右侧变为ConstantExpression与价值1,我们将调用替换为ParameterExpression itself.

¹ 将来,我想要一种方法ParameterExpression并返回一个Expression根据该参数进行评估。这样我就可以聚合生成的函数。我还没到那儿。 ² 将来,我希望发布一个通用库,用于将 LINQ 表达式用作符号数学。


我使用以下代码编写了几个符号数学功能的基础知识表达访问者 http://msdn.microsoft.com/en-us/library/system.linq.expressions.expressionvisitor(VS.100).aspx输入.NET 4。它并不完美,但它看起来像是可行解决方案的基础。

  • Symbolic是一个公共静态类,公开类似的方法Expand, Simplify, and PartialDerivative
  • ExpandVisitor是扩展表达式的内部辅助类型
  • SimplifyVisitor是简化表达式的内部辅助类型
  • DerivativeVisitor是一个内部辅助类型,它采用表达式的导数
  • ListPrintVisitor是一个内部辅助类型,它转换Expression到 Lisp 语法的前缀表示法

Symbolic

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();
    }
}

扩展表达式ExpandVisitor

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;
    }
}

求导数DerivativeVisitor

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;
    }
}

简化表达式SimplifyVisitor

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;
    }
}

设置表达式的显示格式ListPrintVisitor

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));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多项式评估的生成方法 的相关文章

随机推荐

  • 为派生类专门化 std::hash 在 gcc 中有效,而不是 clang

    我正在努力专攻std hash对于派生类 迄今为止最好的方法是基于这个答案 https stackoverflow com a 31213703 620382 include
  • scala ArrayBuffer 删除带有谓词的所有元素

    Scala 在过滤不可变序列方面非常优雅 var l List 1 2 3 4 5 6 l l filter 2 1 但是如何使用像 ArrayBuffer 这样的可变集合来做到这一点呢 我发现的只是删除单个元素或切片 或者从另一个序列中删
  • 如何在弹出菜单中使用单选按钮?

    我正在尝试创建一个包含可选单选按钮的弹出菜单 以便更改视图类型 例如图库 卡片 滑动 网格 列表等 我遇到的问题是 PopupMenu 有自己的用于选择值的回调 Radio 和 RadioListTile 也是如此 忽略RadioListT
  • 自动将调试器附加到 Eclipse 中的新 Java 子进程

    我有一个 Java 进程 它使用 ProcessBuilder 等生成一个新的 JVM 在调试时 是否可以让 Eclipse 将调试器附加到新的子进程 更好的是 是否有任何插件在注意到新的子进程时会自动执行此操作 我被告知 虽然还没见过 V
  • 哈希表真的可以是 O(1) 吗?

    哈希表可以实现 O 1 似乎是常识 但这对我来说从来没有意义 有人可以解释一下吗 我想到了以下两种情况 A 该值是一个小于哈希表大小的 int 因此 该值是它自己的哈希值 因此不存在哈希表 但即使有 也会是 O 1 并且效率仍然很低 B 您
  • 在 Podfile 中声明架构

    有没有办法将架构包含在 CocoaPods 中Podfile 我正在尝试为 32 位和 64 位构建我的应用程序 但是当我切换到Standard architectures including 64 bit 在我的项目的构建设置中 它抱怨我
  • css:覆盖活动链接样式?

    我的 css 中有以下选择器 a active position relative top 1px 因此 每个链接在按下时都会有这个小按钮效果 我怎样才能防止特定链接的这种行为 例如我的网站上有一个 返回顶部 链接 不应该有这种行为 a b
  • 标准 Treeview 的 C# 替代品?

    我想找到提供的 System Windows Form Treeview 的替代品 我需要以下改进 多项选择项目 更好的性能 标准小部件的性能简直太糟糕了 特别是在添加一长串项目时 在树视图小部件内拖放项目时滚动 我可能会忘记一些 但这些非
  • s3 安装在容器内。如何将其暴露给主机?

    我一直在考虑是否有一个容器可以安装 s3 桶并将其暴露在外面 I used https github com FindHotel aws s3 mount https github com FindHotel aws s3 mount将 s
  • 拖放文本视图

    我必须拖动 但无法完美拖动它 问题是 1 我必须拖动两到三次才能将其带到所需的位置 因此 textview 不能顺利跟随手指移动 2 如果我向上移动文本视图 它只会向下移动 我提供了触摸事件上textview的代码 请帮忙 提前致谢 fin
  • 如何使用 Unix 套接字对来通信 Rust 和 Ruby 进程

    我正在尝试使用 Unix 套接字对将 Rust 进程与 Ruby 子进程进行通信 我只使用 Ruby 尝试过同样的操作 它可以工作 但我似乎无法让它与 Rust 一起工作 我尝试将 rust socket 文件描述符传递给Ruby脚本 将
  • python 中的聚合时间序列

    我们如何按小时或分钟粒度聚合时间序列 如果我有如下所示的时间序列 那么我希望这些值按小时聚合 pandas 是否支持它 或者是否有一种在 python 中实现它的好方法 timestamp value 2012 04 30T22 25 31
  • 应用内购买产品 ID 是否必须以反向 DNS 开头?

    应用内购买产品 ID 是否必须以反向 DNS 开头 例如com mycompany My Awesome Game Level Pack 1或者它可以只是独立的吗Level Pack 1 产品 ID 可以是您想要的任何内容 但建议您遵循反向
  • 使用 rma.glmm 计算估计值:当 2 个估计值相同时出错

    我正在使用 rma glmm 来计算两项不同研究的元比例 例如 6 个月时出现 xi 和未出现 xii 不良事件的个体比例 library metafor 6 months study c 1 2 ni c 41 19 xi c 26 14
  • 浏览器后退按钮未更新页面

    我使用 jquery 单击事件在井号标记后设置 URL URL 设置正确 但当我使用浏览器后退按钮时 它不会将我带到上一页 在我的点击事件之前 URL 如下所示 http example com menu php home 我的点击事件如下
  • 如何使用 JavaZOOM JLayer 库播放/暂停 mp3 文件?

    如何向以下代码添加播放 暂停按钮 import javazoom jl player Player try FileInputStream fis new FileInputStream mysong mp3 Player playMP3
  • 更新至 Safari 12.0 - Java 插件不再列出

    更新到后Safari 版本 12 0 下面的Java插件Safari gt 首选项 gt 网站 gt 插件不再列出 因此 Java Applet 不能在不安全模式下运行 有没有办法启用 Java 插件或运行 Java 小程序 在 macOS
  • Pandas:条件组特定计算

    假设我有一个带有键 例如客户 ID 和两个数字列 C1 和 C2 的表 我想按键 客户 对行进行分组 并在其列上运行一些聚合器 例如 sum 和 Mean 在计算组聚合器之后 我想将结果分配回 DataFrame 中的每个客户行 因为一些客
  • ReactJS HREF 导致状态丢失

    我有一个名为 EnrollForm 的父组件 带有一个 BrowserRouter 该组件路由到不同的子组件 这些子组件是我的整个 EnrollForm 的页面 每次填写子组件页面并单击下一个 btn 时 所有表单字段都会保存到子组件状态
  • 多项式评估的生成方法

    我试图想出一种优雅的方法来处理一些生成的多项式 对于这个问题 我们将 专门 关注以下情况 order是生成的参数n三阶多项式 其中 n order 1 i是 0 n 范围内的整数参数 多项式在 x j 处有零点 其中 j 1 n 且 j i