游乐游手机版
首页/编程语言/文章详情

SymPy自动因式分解:从面积拼图到代数恒等式

时间:2026-06-19 06:44
利用SymPy自动因式分解并提取常数项,为形如(x+a)(x+b)的多项式生成矩形拼图的宽高和坐标,解决了Manim演示中不同公式需手动调整布局的痛点,实现了一类公式共用统一布局生成器。

今天专门解决一个非常具体的痛点——因式分解公式的可视化演示。

用SymPy自动因式分解:从面积拼图到代数恒等式

问题说穿了很简单:

你想用 Manimx2+5x+6=(x+2)(x+3)x2 + 5x + 6 = (x+2)(x+3) 通过“十字相乘”的面积模型展示出来。第一步你就得琢磨——这个大矩形怎么拆成四块?哪块是 x2x^22x2x3x3x6?它们的边长和位置又该怎么算?全得手动来。

好,这个问题搞定了。那么换个公式呢?改成 x2+7x+12x^2 + 7x + 12,布局又得从头算一遍。

这就引出最核心的问题了:有没有办法只告诉程序“我要做这个多项式的拼图证明”,它就能自动把尺寸和坐标全部算好?

答案是:有,用 SymPy

它能根据代数式的结构自动推导出几何布局,让你从“一个公式写一套代码”进化到“一类公式共用一套生成器”。

1. 痛点场景还原:公式一换,布局全乱

先来看一个典型的“手工布局”案例。

我们要把 x2+5x+6=(x+2)(x+3)x^2 + 5x + 6 = (x+2)(x+3) 的面积模型画出来,大矩形分成四块。代码大概长这样:

from manim import *class ManualX2Plus5xPlus6(Scene):
    def construct(self):
        x = 2  # 给 x 取个值来画图
        # 手动定义四块的宽高
        sq_x2 = Rectangle(width=x, height=x, color=BLUE, fill_opacity=0.4)
        rec_3x = Rectangle(width=3, height=x, color=RED, fill_opacity=0.4)
        rec_2x = Rectangle(width=x, height=2, color=RED, fill_opacity=0.4)
        rec_6 = Rectangle(width=3, height=2, color=GREEN, fill_opacity=0.4)
        # 手动拼装:左下角是 x^2,右边是 3x,上边是 2x,右上是 6
        sq_x2.shift(LEFT * (3 / 2) + DOWN * (2 / 2))
        rec_3x.next_to(sq_x2, RIGHT, buff=0)
        rec_2x.next_to(sq_x2, UP, buff=0)
        rec_6.next_to(rec_3x, UP, buff=0)
        self.play(Create(sq_x2), Create(rec_3x), Create(rec_2x), Create(rec_6))
        self.wait(1)

这段代码跑是能跑,但代价是每一处数字都是针对 x2+5x+6x^2 + 5x + 6 硬编码的。如果要改成 x2+7x+12=(x+3)(x+4)x^2 + 7x + 12 = (x+3)(x+4),那么:

  • 常数项从 2、3 变成 3、4;
  • rec_3x 的宽度要改成 4;
  • rec_2x 的高度要改成 3;
  • 小矩形 rec_6 的宽高要改成 4 和 3;
  • shift 里的偏移量也得跟着重新算。

每一次换公式都是一次手工劳动,而且还很容易出错。要是公式结构复杂一点,比如二次项系数不是 1,或者涉及到三项展开,这种手动模式基本就撑不住了。

2. SymPy 解决方案:因式分解 → 几何布局

SymPy 的真正厉害之处就在这里:它可以对多项式进行因式分解或展开,然后自动把每一项的系数和次数全都提取出来

而我们要做的,就是根据这些信息,自动生成对应的矩形拼图布局。

整个流程是这样的:

  1. 输入一个多项式字符串,比如 "x**2 + 5*x + 6"
  2. 让 SymPy 对它做因式分解,得到 (x + 2)*(x + 3)
  3. 从因式结果中读出两个一次式的常数项(2 和 3),从展开式中读出各项系数(1, 5, 6);
  4. 自动生成四个矩形块:x2x^2(边长 xx)、2x2x(宽 2 高 xx)、3x3x(宽 xx 高 3)、6(宽 2 高 3),然后根据这些边长自动算出它们左下角的坐标;
  5. 最后把布局信息打包成一个统一的数据结构,交给 Manim 去渲染。

这样做最大的好处是什么?不管输入是 x2+7x+12x^2 + 7x + 12x23x+2x^2 - 3x + 2,甚至是带参数的 x2+(a+b)x+abx^2 + (a+b)x + ab布局生成的逻辑完全一样——你只需要改一行输入字符串。

下面是一段纯 SymPy 的布局生成器代码,不依赖 Manim,可以直接在 Jupyter 里跑:

from sympy import symbols, factor, expand, Poly
from sympy.abc import xdef generate_layout(poly_expr):
    """
    输入:一个关于 x 的多项式(可因式分解为 (x+a)(x+b))
    输出:四个矩形的布局信息列表,每个矩形包括 (标签, 宽, 高, x坐标, y坐标)
    """
    # 因式分解
    factored = factor(poly_expr)            # 例如 (x + 2)*(x + 3)
    # 确保是两个一次因式
    if not factored.is_Mul:
        raise ValueError("多项式不能分解为两个一次因式")
    factors = factored.args
    if len(factors) != 2:
        raise ValueError("暂时只支持两个一次因式")
    # 提取常数项 a, b
    a = None
    b = None
    for fac in factors:
        if fac.is_Add:
            p = Poly(fac, x)
            if p.degree() == 1:
                const = p.coeff_monomial(1)  # 系数 1
                const_term = p.coeff_monomial(0)  # 常数项
                if const == 1:
                    val = const_term
                else:
                    val = const_term / const
            if a is None:
                a = val
            else:
                b = val
    # 展开式获取各项
    expanded = expand(poly_expr)
    poly = Poly(expanded, x)
    coeff_x2 = poly.coeff_monomial(2)  # x^2 系数
    coeff_x  = poly.coeff_monomial(1)  # x 系数
    const    = poly.coeff_monomial(0)  # 常数项
    # 返回布局,宽和高用数值表达式(含 x),留给 Manim 代入 x_val
    layout = [
        {"label": "x^2", "w": "x", "h": "x", "x0": 0, "y0": 0},
        {"label": f"{b}x", "w": b, "h": "x", "x0": "x", "y0": 0},
        {"label": f"{a}x", "w": "x", "h": a, "x0": 0, "y0": "x"},
        {"label": f"{a*b}", "w": b, "h": a, "x0": "x", "y0": "x"},
    ]
    return layout, a, b# 示例:x^2 + 5x + 6
layout, a, b = generate_layout(x**2 + 5*x + 6)
print("a =", a, " b =", b)
for item in layout:
    print(item)

输出结果如下:

a = 2  b = 3
{'label': 'x^2', 'w': 'x', 'h': 'x', 'x0': 0, 'y0': 0}
{'label': '3x', 'w': 3, 'h': 'x', 'x0': 'x', 'y0': 0}
{'label': '2x', 'w': 'x', 'h': 2, 'x0': 0, 'y0': 'x'}
{'label': '6', 'w': 3, 'h': 2, 'x0': 'x', 'y0': 'x'}

可以看到,矩形的宽高和坐标全部由 ab 决定,而 a,b 是从 SymPy 的因式分解结果中自动提取的。换个多项式,只需要改一行输入,布局自动就能生成。

3. Manim 联动实战:通用因式分解拼图动画

现在我们把这个自动布局引擎接入 Manim,做一个通用场景:只需要在开头指定一个多项式,动画就会自动展示对应的面积拼图,并标注出公式。

完整代码如下:

from manim import *
from sympy import factor, Poly
from sympy.abc import xclass AutoFactorPuzzle(Scene):
    def construct(self):
        # ========== 1. 在这里输入你要讲的多项式 ==========
        poly_expr = x**2 + 5 * x + 6  # 试着改成 x**2 + 7*x + 12 看看!
        x_val = 1.5  # 动画中 x 的具体取值(可调)
        # ========== 2. SymPy 自动分析多项式 ==========
        factored = factor(poly_expr)
        if not factored.is_Mul or len(factored.args) != 2:
            raise ValueError("多项式需能分解为两个一次因式 (x+a)(x+b)")
        # 提取 a, b
        roots = []
        for fac in factored.args:
            p = Poly(fac, x)
            if p.degree() != 1:
                raise ValueError("因式必须是一次式")
            coeffs = p.all_coeffs()
            root = -coeffs[1] / coeffs[0]
            roots.append(root)
        a, b = float(roots[0]), float(roots[1])  # 常数项 a, b
        # ========== 3. 根据 a, b 生成矩形布局 ==========
        blocks = [
            {"label": "x^2", "w": x_val, "h": x_val, "x0": 0, "y0": 0, "color": BLUE},
            {
                "label": f"{abs(b)} \times x",
                "w": abs(b),
                "h": x_val,
                "x0": x_val,
                "y0": 0,
                "color": RED,
            },
            {
                "label": f"{abs(a)} \times x",
                "w": x_val,
                "h": abs(a),
                "x0": 0,
                "y0": x_val,
                "color": YELLOW,
            },
            {
                "label": f"{abs(b)} \times {abs(a)}",
                "w": abs(b),
                "h": abs(a),
                "x0": x_val,
                "y0": x_val,
                "color": GREEN,
            },
        ]
        # ========== 4. Manim 绘制 ==========
        for blk in blocks:
            rect = Rectangle(
                width=blk["w"],
                height=blk["h"],
                color=blk["color"],
                fill_opacity=0.4,
                stroke_width=1,
            )
            rect.move_to([blk["x0"] + blk["w"] / 2, blk["y0"] + blk["h"] / 2, 0])
            rect.shift(LEFT * 2 + DOWN)
            label = MathTex(f"{blk['label']}", font_size=16)
            label.move_to(rect.get_center())
            self.play(Create(rect), Write(label))
        self.wait(0.5)
        # 显示等式
        eq = MathTex(
            f"{{x}}^2 + {poly_expr.coeff(x,1)}x + {poly_expr.coeff(x,0)}",
            "=",
            f"(x{a if a<0 else abs(a)})(x{b if b<0 else abs(b)})",
            font_size=20,
        ).shift(DOWN * 1.5)
        self.play(Write(eq))
        self.wait(2)

关键点需要说明一下

  • 多项式的输入只改 poly_expr = ... 这一行,一整段代码就能自动绘制出对应的十字相乘面积图;
  • SymPy 的 factor 自动拆出一次因式,Poly 帮我们提取出系数,ab 直接成为矩形的边长参数;
  • 整个布局的坐标逻辑只写了一次,通过 abx_val 计算出 blocks,完全没有手动偏移的操作。

试试把 poly_expr 改成 x**2 + 7*x + 12,重新运行一次。动画会立刻切换成 x2x^2(蓝)、4x4x(红)、3x3x(黄)、1212(绿)的四块拼图,等式也会同步更新为 x2+7x+12=(x+4)(x+3)x^2+7x+12=(x+4)(x+3)

4. 效果展示说明

运行上面这个 AutoFactorPuzzle,你会看到:

  1. 四块矩形依次浮现:蓝色 x2x^2 在左下角,右侧是一块红色的 bxbx,上方是一块黄色的 axax,右上角是绿色的常数块 abab。所有块之间严丝合缝,因为它们的坐标和边长都来自同一个因式分解结果。
  2. 标签 x2x^2bxbxaxaxabab 精准地位于每块的中心,清晰对应着代数项。
  3. 画面下方会显示因式分解的等式——左边是展开式,右边是因式乘积。学生可以立刻把图形和公式对应起来。

更关键的是:换一个多项式只需要改一行代码,动画逻辑完全复用。

如果想一次性展示多个公式的对比,只需要建几个不同的场景实例即可。

这意味着,制作一套完整的“因式分解几何证明”微课,可以从一天的工作量缩短到一小时。

5. 小结

SymPy 在这个场景里扮演的角色,本质上是一个代数结构的自动解析器

传统方法当然也能拼出图,但你需要用大脑去“解析”公式,再手动翻译成矩形的宽高和位置;

SymPy 帮你自动完成了“因式分解 → 提取系数 → 生成几何参数”的全过程,让你可以专注于教学设计本身和动画的视觉效果美化。

这个模式可以轻松扩展到:

  • 二次三项式的十字相乘面积模型(就是本文的例子);
  • 完全平方和平方差公式的拼图证明;
  • 多项式乘法的面积表示,比如 (x+a)(x+b)(x+c)(x+a)(x+b)(x+c) 的体积模型;
  • 甚至更复杂的恒等式,只要你能把代数结构映射为空间的分割。
来源:https://juejin.cn/post/7650451521307852843
上一篇Qt高级开发QListWidget图标布局实战指南 下一篇Java并发编程synchronized关键字保证线程安全的原理
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
详解如何使用Apache服务器进行防盗链配置步骤
编程语言 · 2026-06-30

详解如何使用Apache服务器进行防盗链配置步骤

Apache使用mod_rewrite模块实现图片防盗链,通过 htaccess文件配置Rewrite规则,检查HTTP_REFERER来源,若非本站域名且来源不为空,则对jpg等常见图片格式返回403禁止访问。此方法能有效阻止大多数盗链行为。

Filebeat日志转发实现步骤详解
编程语言 · 2026-06-30

Filebeat日志转发实现步骤详解

Filebeat通过配置输入源读取日志,输出目标转发至Elasticsearch或Logstash。安装后编辑filebeat yml文件,指定日志路径和输出地址。支持直接转发或经Logstash处理。通过systemctl启动并验证数据到达,可选SSL加密和多行日志合并配置。

手把手教你如何在CentOS上使用PhpStorm构建项目的详细步骤
编程语言 · 2026-06-30

手把手教你如何在CentOS上使用PhpStorm构建项目的详细步骤

在CentOS上使用PHPStorm构建项目需先准备环境:安装Java、PHP及扩展、Nginx、MariaDB并开放端口。然后安装配置PHPStorm,设置SSH解释器与Web服务器映射。导入或创建项目后安装Composer依赖,调整php ini。配置SFTP部署并同步文件,最后设置Xdebug进行调试运行。

CentOS下GitLab集成其他工具的详细配置方法与完整指南
编程语言 · 2026-06-30

CentOS下GitLab集成其他工具的详细配置方法与完整指南

在CentOS平台中,GitLab通过Webhooks、API与CI CD配置,深度集成Jenkins、SonarQube、Docker及Slack,构建代码托管、自动构建、质量检查与协作通知的自动化链路,覆盖开发、测试、部署全流程,实现从提交到上线的自动化,大幅提升团队效率与交付质量,推动开发运维一体化。

CentOS设置Node.js定时任务的方法
编程语言 · 2026-06-30

CentOS设置Node.js定时任务的方法

在CentOS上为Node js应用设置定时任务常用两种方案:systemd适合长期运行服务,需创建服务文件并配置开机自启;cron更灵活,适合定期唤醒任务,通过编辑crontab添加时间计划和执行命令。两种方法均需指定Node js路径和应用入口。