这该怎么做?高数求解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了这该怎么做?高数求解相关的知识,希望对你有一定的参考价值。
大家都知道,AI (神经网络) 连加减法这样的简单算术都做不好:可现在,AI已经懂得微积分,把魔爪伸向你最爱的高数了。 它不光会求不定积分:
还能解常微分方程:
一阶二阶都可以。
这是Facebook发表的新模型,1秒给出的答案,超越了Mathematica和Matlab这两只付费数学软件30秒的成绩。 团队说,这是Seq2Seq和Transformer搭配食用的结果。 用自然语言处理 (NLP) 的方法来理解数学,果然行得通。 这项成果,已经在推特上获得了1700赞。许多小伙伴表示惊奇,比如: “感谢你们!在我原本的想象中,这完全是不可能的!”
而且,据说算法很快就要开源了:
到时候让付费软件怎么办?
巨大数据集的生成姿势要训练模型做微积分题目,最重要的前提就是要有大大大的数据集。 这里有,积分数据集和常微分方程数据集的制造方法:函数,和它的积分首先,就是要做出“一个函数&它的微分”这样的数据对。团队用了三种方法: 第一种是正向生成 (Fwd) ,指生成随机函数 (最多n个运算符) ,再用现成的工具求积分。把工具求不出的函数扔掉。 第二种是反向生成 (Bwd) ,指生成随机函数,再对函数求导。填补了第一种方法收集不到的一些函数,因为就算工具求不出积分,也一定可以求导。 第三种是用了分部积分的反向生成 (Ibp) 。前面的反向生成有个问题,就是不太可能覆盖到f(x)=x3sin(x)的积分: F(x)=-x3cos(x)+3x2sin(x)+6xcos(x)-6sin(x) 因为这个函数太长了,随机生成很难做到。 另外,反向生成的产物,大多会是函数的积分比函数要短,正向生成则相反。 为了解决这个问题,团队用了分部积分:生成两个随机函数F和G,分别算出导数f和g。 如果fG已经出现在前两种方法得到的训练集里,它的积分就是已知,可以用来求出Fg: ∫Fg=FG-∫fG 反过来也可以,如果Fg已经在训练集里,就用它的积分求出fG。 每求出一个新函数的积分,就把它加入训练集。 如果fG和Fg都不在训练集里,就重新生成一对F和G。 如此一来,不借助外部的积分工具,也能轻松得到x10sin(x)这样的函数了。一阶常微分方程,和它的解从一个二元函数F(x,y)说起。 有个方程F(x,y)=c,可对y求解得到y=f(x,c)。就是说有一个二元函数f,对任意x和c都满足:
再对x求导,就得到一个微分方程:
fc表示从x到f(x,c)的映射,也就是这个微分方程的解。 这样,对于任何的常数c,fc都是一阶微分方程的解。 把fc替换回y,就有了整洁的微分方程:
这样一来,想做出“一阶常微分方程&解”的成对数据集,只要生成一个f(x,c),对c有解的那种,再找出它满足的微分方程F就可以了,比如:
二阶常微分方程,和它的解二阶的原理,是从一阶那里扩展来的,只要把f(x,c)变成f(x,c1,c2) ,对c2有解。 微分方程F要满足:
把它对x求导,会得到:
fc1,c2表示,从x到f(x,c1,c2)的映射。 如果这个方程对c1有解,就可以推出另外一个三元函数G,它对任意x都满足:
再对x求导,就会得到:
最后,整理出清爽的微分方程:
它的解就是fc1,c2。 至于生成过程,举个例子:
现在,求积分和求解微分方程两个训练集都有了。那么问题也来了,AI要怎么理解这些复杂的式子,然后学会求解方法呢?
将数学视作自然语言积分方程和微分方程,都可以视作将一个表达式转换为另一个表达式,研究人员认为,这是机器翻译的一个特殊实例,可以用NLP的方法来解决。 第一步,是将数学表达式以树的形式表示。 运算符和函数为内部节点,数字、常数和变量等为叶子节点。 比如 3x^2 + cos(2x) - 1 就可以表示为:
再举一个复杂一点的例子,这样一个偏微分表达式:
用树的形式表示,就是:
采用树的形式,就能消除运算顺序的歧义,照顾优先级和关联性,并且省去了括号。在没有空格、标点符号、多余的括号这样的无意义符号的情况下,不同的表达式会生成不同的树。表达式和树之间是一一对应的。 第二步,引入seq2seq模型。 seq2seq模型具有两种重要特性: 输入和输出序列都可以具有任意长度,并且长度可以不同。 输入序列和输出序列中的字词不需要一一对应。 因此,seq2seq模型非常适合求解微积分的问题。 使用seq2seq模型生成树,首先,要将树映射到序列。 使用前缀表示法,将每个父节点写在其子节点之前,从左至右列出。 比如 2 + 3 * (5 + 2),表示为树是:
表示为序列就是 [+ 2 * 3 + 5 2]。 树和前缀序列之间也是一一映射的。 第三步,生成随机表达式。 要创建训练数据,就需要生成随机数学表达式。前文已经介绍了数据集的生成策略,这里着重讲一下生成随机表达式的算法。 使用n个内部节点对表达式进行统一采样并非易事。比如递归这样的方法,就会倾向于生成深树而非宽树,偏左树而非偏右树,实际上是无法以相同的概率生成不同种类的树的。 所以,以随机二叉树为例,具体的方法是:从一个空的根节点开始,在每一步中确定下一个内部节点在空节点中的位置。重复进行直到所有内部节点都被分配为止。
不过,在通常情况下,数学表达式树不一定是二叉树,内部节点可能只有1个子节点。如此,就要考虑根节点和下一内部节点参数数量的二维概率分布,记作 L(e,n)。
接下来,就是对随机树进行采样,从可能的运算符和整数、变量、常量列表中随机选择内部节点及叶子节点来对树进行“装饰”。 最后,计算表达式的数量。 经由前面的步骤,可以看出,表达式实际上是由一组有限的变量、常量、整数和一系列运算符组成的。 于是,问题可以概括成: 最多包含n个内部节点的树 一组p1个一元运算符(如cos,sin,exp,log) 一组p2个二进制运算符(如+,-,×,pow) 一组L个叶子值,其中包含变量(如x,y,z),常量(如e,π),整数(如 -10,…,10) 如果p1 = 0,则表达式用二叉树表示。 这样,具有n个内部节点的二叉树恰好具有n + 1个叶子节点。每个节点和叶子可以分别取p1和L个不同的值。 具有n个二进制运算符的表达式数量就可以表示为:
如果p1 > 0,表达式数量则为:
可以观察到,叶子节点和二元运算符的数量会明显影响问题空间的大小。
△不同数目运算符和叶子节点的表达式数量
胜过商业软件实验中,研究人员训练seq2seq模型预测给定问题的解决方案。采用的模型,是8个注意力头(attention head),6层,512维的Transformer模型。 研究人员在一个拥有5000个方程的数据集中,对模型求解微积分方程的准确率进行了评估。 结果表明,对于微分方程,波束搜索解码能大大提高模型的准确率。
而与最先进的商业科学计算软件相比,新模型不仅更快,准确率也更高。
在包含500个方程的测试集上,商业软件中表现最好的是Mathematica。 比如,在一阶微分方程中,与使用贪婪搜索解码算法(集束大小为1)的新模型相比,Mathematica不落下风,但新方法通常1秒以内就能解完方程,Mathematica的解题时间要长的多(限制时间30s,若超过30s则视作没有得到解)。
而当新方法进行大小为50的波束搜索时,模型准确率就从81.2%提升到了97%,远胜于Mathematica(77.2%) 并且,在某一些Mathematica和Matlab无力解决的问题上,新模型都给出了有效解。
△商业科学计算软件没有找到解的方程
邀请AI参加IMO这个会解微积分的AI一登场,就吸引了众多网友的目光,引发热烈讨论。网友们纷纷称赞:鹅妹子嘤。 有网友这样说道: 这篇论文超级有趣的地方在于,它有可能解决复杂度比积分要高得高得高得多的问题。
还有网友认为,这项研究太酷了,该模型能够归纳和整合一些sympy无法实现的功能。
不过,也有网友认为,在与Mathematica的对比上,研究人员的实验设定显得不够严谨。 默认设置下,Mathematica是在复数域中进行计算的,这会增加其操作的难度。但作者把包含复数系数的表达式视作“无效”。所以他们在使用Mathematica的时候将设置调整为实数域了?
我很好奇Mathematica是否可以解决该系统无法解决的问题。 30s的限制时间对于计算机代数系统有点武断了。
但总之,面对越来越机智的AI,已经有人发起了挑战赛,邀请AI挑战IMO金牌。
Facebook AI研究院出品 这篇论文有两位共同一作。 Guillaume Lample,来自法国布雷斯特,是Facebook AI研究院、皮埃尔和玛丽·居里大学在读博士。他曾于巴黎综合理工学院和CMU分别获得数学与计算机科学和人工智能硕士学位。 2014年进入Facebook实习。 Franois Charton,Facebook AI研究院的客座企业家(Visiting entrepreneur),主要研究方向是数学和因果关系。
传送门https://arxiv.org/abs/1912.01412 https://news.ycombinator.com/item?id=21084748
————
编辑 ∑Gemini
来源:新浪科技 参考技术A 扇形面积 S = (1/2)αR^2,
当 α 减少 30', dα = -0.5° = -π/360,
dS = (1/2)R^2dα = -(1/2)100^2 · π/360 = -43.63 平方厘米
扇形面积减少约 43.63 平方厘米;
当 R 增加 1 厘米, dR = 1
dS = αRdR = 100 · 1 · 60π/180 = 104.72 平方厘米
扇形面积增加约 104.72 平方厘米。本回答被提问者和网友采纳 参考技术B 大家都知道,AI (神经网络) 连加减法这样的简单算术都做不好:
可现在,AI已经懂得微积分,把魔爪伸向你最爱的高数了。 它不光会求不定积分:
还能解常微分方程:
一阶二阶都可以。
这是Facebook发表的新模型,1秒给出的答案,超越了Mathematica和Matlab这两只付费数学软件30秒的成绩。 团队说,这是Seq2Seq和Transformer搭配食用的结果。 用自然语言处理 (NLP) 的方法来理解数学,果然行得通。 这项成果,已经在推特上获得了1700赞。许多小伙伴表示惊奇,比如: “感谢你们!在我原本的想象中,这完全是不可能的!”
而且,据说算法很快就要开源了:
到时候让付费软件怎么办?
巨大数据集的生成姿势要训练模型做微积分题目,最重要的前提就是要有大大大的数据集。 这里有,积分数据集和常微分方程数据集的制造方法:函数,和它的积分首先,就是要做出“一个函数&它的微分”这样的数据对。团队用了三种方法: 第一种是正向生成 (Fwd) ,指生成随机函数 (最多n个运算符) ,再用现成的工具求积分。把工具求不出的函数扔掉。 第二种是反向生成 (Bwd) ,指生成随机函数,再对函数求导。填补了第一种方法收集不到的一些函数,因为就算工具求不出积分,也一定可以求导。 第三种是用了分部积分的反向生成 (Ibp) 。前面的反向生成有个问题,就是不太可能覆盖到f(x)=x3sin(x)的积分: F(x)=-x3cos(x)+3x2sin(x)+6xcos(x)-6sin(x) 因为这个函数太长了,随机生成很难做到。 另外,反向生成的产物,大多会是函数的积分比函数要短,正向生成则相反。 为了解决这个问题,团队用了分部积分:生成两个随机函数F和G,分别算出导数f和g。 如果fG已经出现在前两种方法得到的训练集里,它的积分就是已知,可以用来求出Fg: ∫Fg=FG-∫fG 反过来也可以,如果Fg已经在训练集里,就用它的积分求出fG。 每求出一个新函数的积分,就把它加入训练集。 如果fG和Fg都不在训练集里,就重新生成一对F和G。 如此一来,不借助外部的积分工具,也能轻松得到x10sin(x)这样的函数了。一阶常微分方程,和它的解从一个二元函数F(x,y)说起。 有个方程F(x,y)=c,可对y求解得到y=f(x,c)。就是说有一个二元函数f,对任意x和c都满足:
再对x求导,就得到一个微分方程:
fc表示从x到f(x,c)的映射,也就是这个微分方程的解。 这样,对于任何的常数c,fc都是一阶微分方程的解。 把fc替换回y,就有了整洁的微分方程:
这样一来,想做出“一阶常微分方程&解”的成对数据集,只要生成一个f(x,c),对c有解的那种,再找出它满足的微分方程F就可以了,比如:
二阶常微分方程,和它的解二阶的原理,是从一阶那里扩展来的,只要把f(x,c)变成f(x,c1,c2) ,对c2有解。 微分方程F要满足:
把它对x求导,会得到:
fc1,c2表示,从x到f(x,c1,c2)的映射。 如果这个方程对c1有解,就可以推出另外一个三元函数G,它对任意x都满足:
再对x求导,就会得到:
最后,整理出清爽的微分方程:
它的解就是fc1,c2。 至于生成过程,举个例子:
现在,求积分和求解微分方程两个训练集都有了。那么问题也来了,AI要怎么理解这些复杂的式子,然后学会求解方法呢?
将数学视作自然语言积分方程和微分方程,都可以视作将一个表达式转换为另一个表达式,研究人员认为,这是机器翻译的一个特殊实例,可以用NLP的方法来解决。 第一步,是将数学表达式以树的形式表示。 运算符和函数为内部节点,数字、常数和变量等为叶子节点。 比如 3x^2 + cos(2x) - 1 就可以表示为:
再举一个复杂一点的例子,这样一个偏微分表达式:
用树的形式表示,就是:
采用树的形式,就能消除运算顺序的歧义,照顾优先级和关联性,并且省去了括号。在没有空格、标点符号、多余的括号这样的无意义符号的情况下,不同的表达式会生成不同的树。表达式和树之间是一一对应的。 第二步,引入seq2seq模型。 seq2seq模型具有两种重要特性: 输入和输出序列都可以具有任意长度,并且长度可以不同。 输入序列和输出序列中的字词不需要一一对应。 因此,seq2seq模型非常适合求解微积分的问题。 使用seq2seq模型生成树,首先,要将树映射到序列。 使用前缀表示法,将每个父节点写在其子节点之前,从左至右列出。 比如 2 + 3 * (5 + 2),表示为树是:
表示为序列就是 [+ 2 * 3 + 5 2]。 树和前缀序列之间也是一一映射的。 第三步,生成随机表达式。 要创建训练数据,就需要生成随机数学表达式。前文已经介绍了数据集的生成策略,这里着重讲一下生成随机表达式的算法。 使用n个内部节点对表达式进行统一采样并非易事。比如递归这样的方法,就会倾向于生成深树而非宽树,偏左树而非偏右树,实际上是无法以相同的概率生成不同种类的树的。 所以,以随机二叉树为例,具体的方法是:从一个空的根节点开始,在每一步中确定下一个内部节点在空节点中的位置。重复进行直到所有内部节点都被分配为止。
不过,在通常情况下,数学表达式树不一定是二叉树,内部节点可能只有1个子节点。如此,就要考虑根节点和下一内部节点参数数量的二维概率分布,记作 L(e,n)。
接下来,就是对随机树进行采样,从可能的运算符和整数、变量、常量列表中随机选择内部节点及叶子节点来对树进行“装饰”。 最后,计算表达式的数量。 经由前面的步骤,可以看出,表达式实际上是由一组有限的变量、常量、整数和一系列运算符组成的。 于是,问题可以概括成: 最多包含n个内部节点的树 一组p1个一元运算符(如cos,sin,exp,log) 一组p2个二进制运算符(如+,-,×,pow) 一组L个叶子值,其中包含变量(如x,y,z),常量(如e,π),整数(如 -10,…,10) 如果p1 = 0,则表达式用二叉树表示。 这样,具有n个内部节点的二叉树恰好具有n + 1个叶子节点。每个节点和叶子可以分别取p1和L个不同的值。 具有n个二进制运算符的表达式数量就可以表示为:
如果p1 > 0,表达式数量则为:
可以观察到,叶子节点和二元运算符的数量会明显影响问题空间的大小。
△不同数目运算符和叶子节点的表达式数量
胜过商业软件实验中,研究人员训练seq2seq模型预测给定问题的解决方案。采用的模型,是8个注意力头(attention head),6层,512维的Transformer模型。 研究人员在一个拥有5000个方程的数据集中,对模型求解微积分方程的准确率进行了评估。 结果表明,对于微分方程,波束搜索解码能大大提高模型的准确率。
而与最先进的商业科学计算软件相比,新模型不仅更快,准确率也更高。
在包含500个方程的测试集上,商业软件中表现最好的是Mathematica。 比如,在一阶微分方程中,与使用贪婪搜索解码算法(集束大小为1)的新模型相比,Mathematica不落下风,但新方法通常1秒以内就能解完方程,Mathematica的解题时间要长的多(限制时间30s,若超过30s则视作没有得到解)。
而当新方法进行大小为50的波束搜索时,模型准确率就从81.2%提升到了97%,远胜于Mathematica(77.2%) 并且,在某一些Mathematica和Matlab无力解决的问题上,新模型都给出了有效解。
△商业科学计算软件没有找到解的方程
邀请AI参加IMO这个会解微积分的AI一登场,就吸引了众多网友的目光,引发热烈讨论。网友们纷纷称赞:鹅妹子嘤。 有网友这样说道: 这篇论文超级有趣的地方在于,它有可能解决复杂度比积分要高得高得高得多的问题。
还有网友认为,这项研究太酷了,该模型能够归纳和整合一些sympy无法实现的功能。
不过,也有网友认为,在与Mathematica的对比上,研究人员的实验设定显得不够严谨。 默认设置下,Mathematica是在复数域中进行计算的,这会增加其操作的难度。但作者把包含复数系数的表达式视作“无效”。所以他们在使用Mathematica的时候将设置调整为实数域了?
我很好奇Mathematica是否可以解决该系统无法解决的问题。 30s的限制时间对于计算机代数系统有点武断了。
但总之,面对越来越机智的AI,已经有人发起了挑战赛,邀请AI挑战IMO金牌。
Facebook AI研究院出品 这篇论文有两位共同一作。 Guillaume Lample,来自法国布雷斯特,是Facebook AI研究院、皮埃尔和玛丽·居里大学在读博士。他曾于巴黎综合理工学院和CMU分别获得数学与计算机科学和人工智能硕士学位。 2014年进入Facebook实习。 Franois Charton,Facebook AI研究院的客座企业家(Visiting entrepreneur),主要研究方向是数学和因果关系。
传送门https://arxiv.org/abs/1912.01412 https://news.ycombinator.com/item?id=21084748
————
编辑 ∑Gemini
来源:新浪科技 参考技术C 大家都知道,AI (神经网络) 连加减法这样的简单算术都做不好:
可现在,AI已经懂得微积分,把魔爪伸向你最爱的高数了。 它不光会求不定积分:
还能解常微分方程:
一阶二阶都可以。
这是Facebook发表的新模型,1秒给出的答案,超越了Mathematica和Matlab这两只付费数学软件30秒的成绩。 团队说,这是Seq2Seq和Transformer搭配食用的结果。 用自然语言处理 (NLP) 的方法来理解数学,果然行得通。 这项成果,已经在推特上获得了1700赞。许多小伙伴表示惊奇,比如: “感谢你们!在我原本的想象中,这完全是不可能的!”
而且,据说算法很快就要开源了:
到时候让付费软件怎么办?
巨大数据集的生成姿势要训练模型做微积分题目,最重要的前提就是要有大大大的数据集。 这里有,积分数据集和常微分方程数据集的制造方法:函数,和它的积分首先,就是要做出“一个函数&它的微分”这样的数据对。团队用了三种方法: 第一种是正向生成 (Fwd) ,指生成随机函数 (最多n个运算符) ,再用现成的工具求积分。把工具求不出的函数扔掉。 第二种是反向生成 (Bwd) ,指生成随机函数,再对函数求导。填补了第一种方法收集不到的一些函数,因为就算工具求不出积分,也一定可以求导。 第三种是用了分部积分的反向生成 (Ibp) 。前面的反向生成有个问题,就是不太可能覆盖到f(x)=x3sin(x)的积分: F(x)=-x3cos(x)+3x2sin(x)+6xcos(x)-6sin(x) 因为这个函数太长了,随机生成很难做到。 另外,反向生成的产物,大多会是函数的积分比函数要短,正向生成则相反。 为了解决这个问题,团队用了分部积分:生成两个随机函数F和G,分别算出导数f和g。 如果fG已经出现在前两种方法得到的训练集里,它的积分就是已知,可以用来求出Fg: ∫Fg=FG-∫fG 反过来也可以,如果Fg已经在训练集里,就用它的积分求出fG。 每求出一个新函数的积分,就把它加入训练集。 如果fG和Fg都不在训练集里,就重新生成一对F和G。 如此一来,不借助外部的积分工具,也能轻松得到x10sin(x)这样的函数了。一阶常微分方程,和它的解从一个二元函数F(x,y)说起。 有个方程F(x,y)=c,可对y求解得到y=f(x,c)。就是说有一个二元函数f,对任意x和c都满足:
再对x求导,就得到一个微分方程:
fc表示从x到f(x,c)的映射,也就是这个微分方程的解。 这样,对于任何的常数c,fc都是一阶微分方程的解。 把fc替换回y,就有了整洁的微分方程:
这样一来,想做出“一阶常微分方程&解”的成对数据集,只要生成一个f(x,c),对c有解的那种,再找出它满足的微分方程F就可以了,比如:
二阶常微分方程,和它的解二阶的原理,是从一阶那里扩展来的,只要把f(x,c)变成f(x,c1,c2) ,对c2有解。 微分方程F要满足:
把它对x求导,会得到:
fc1,c2表示,从x到f(x,c1,c2)的映射。 如果这个方程对c1有解,就可以推出另外一个三元函数G,它对任意x都满足:
再对x求导,就会得到:
最后,整理出清爽的微分方程:
它的解就是fc1,c2。 至于生成过程,举个例子:
现在,求积分和求解微分方程两个训练集都有了。那么问题也来了,AI要怎么理解这些复杂的式子,然后学会求解方法呢?
将数学视作自然语言积分方程和微分方程,都可以视作将一个表达式转换为另一个表达式,研究人员认为,这是机器翻译的一个特殊实例,可以用NLP的方法来解决。 第一步,是将数学表达式以树的形式表示。 运算符和函数为内部节点,数字、常数和变量等为叶子节点。 比如 3x^2 + cos(2x) - 1 就可以表示为:
再举一个复杂一点的例子,这样一个偏微分表达式:
用树的形式表示,就是:
采用树的形式,就能消除运算顺序的歧义,照顾优先级和关联性,并且省去了括号。在没有空格、标点符号、多余的括号这样的无意义符号的情况下,不同的表达式会生成不同的树。表达式和树之间是一一对应的。 第二步,引入seq2seq模型。 seq2seq模型具有两种重要特性: 输入和输出序列都可以具有任意长度,并且长度可以不同。 输入序列和输出序列中的字词不需要一一对应。 因此,seq2seq模型非常适合求解微积分的问题。 使用seq2seq模型生成树,首先,要将树映射到序列。 使用前缀表示法,将每个父节点写在其子节点之前,从左至右列出。 比如 2 + 3 * (5 + 2),表示为树是:
表示为序列就是 [+ 2 * 3 + 5 2]。 树和前缀序列之间也是一一映射的。 第三步,生成随机表达式。 要创建训练数据,就需要生成随机数学表达式。前文已经介绍了数据集的生成策略,这里着重讲一下生成随机表达式的算法。 使用n个内部节点对表达式进行统一采样并非易事。比如递归这样的方法,就会倾向于生成深树而非宽树,偏左树而非偏右树,实际上是无法以相同的概率生成不同种类的树的。 所以,以随机二叉树为例,具体的方法是:从一个空的根节点开始,在每一步中确定下一个内部节点在空节点中的位置。重复进行直到所有内部节点都被分配为止。
不过,在通常情况下,数学表达式树不一定是二叉树,内部节点可能只有1个子节点。如此,就要考虑根节点和下一内部节点参数数量的二维概率分布,记作 L(e,n)。
接下来,就是对随机树进行采样,从可能的运算符和整数、变量、常量列表中随机选择内部节点及叶子节点来对树进行“装饰”。 最后,计算表达式的数量。 经由前面的步骤,可以看出,表达式实际上是由一组有限的变量、常量、整数和一系列运算符组成的。 于是,问题可以概括成: 最多包含n个内部节点的树 一组p1个一元运算符(如cos,sin,exp,log) 一组p2个二进制运算符(如+,-,×,pow) 一组L个叶子值,其中包含变量(如x,y,z),常量(如e,π),整数(如 -10,…,10) 如果p1 = 0,则表达式用二叉树表示。 这样,具有n个内部节点的二叉树恰好具有n + 1个叶子节点。每个节点和叶子可以分别取p1和L个不同的值。 具有n个二进制运算符的表达式数量就可以表示为:
如果p1 > 0,表达式数量则为:
可以观察到,叶子节点和二元运算符的数量会明显影响问题空间的大小。
△不同数目运算符和叶子节点的表达式数量
胜过商业软件实验中,研究人员训练seq2seq模型预测给定问题的解决方案。采用的模型,是8个注意力头(attention head),6层,512维的Transformer模型。 研究人员在一个拥有5000个方程的数据集中,对模型求解微积分方程的准确率进行了评估。 结果表明,对于微分方程,波束搜索解码能大大提高模型的准确率。
而与最先进的商业科学计算软件相比,新模型不仅更快,准确率也更高。
在包含500个方程的测试集上,商业软件中表现最好的是Mathematica。 比如,在一阶微分方程中,与使用贪婪搜索解码算法(集束大小为1)的新模型相比,Mathematica不落下风,但新方法通常1秒以内就能解完方程,Mathematica的解题时间要长的多(限制时间30s,若超过30s则视作没有得到解)。
而当新方法进行大小为50的波束搜索时,模型准确率就从81.2%提升到了97%,远胜于Mathematica(77.2%) 并且,在某一些Mathematica和Matlab无力解决的问题上,新模型都给出了有效解。
△商业科学计算软件没有找到解的方程
邀请AI参加IMO这个会解微积分的AI一登场,就吸引了众多网友的目光,引发热烈讨论。网友们纷纷称赞:鹅妹子嘤。 有网友这样说道: 这篇论文超级有趣的地方在于,它有可能解决复杂度比积分要高得高得高得多的问题。
还有网友认为,这项研究太酷了,该模型能够归纳和整合一些sympy无法实现的功能。
不过,也有网友认为,在与Mathematica的对比上,研究人员的实验设定显得不够严谨。 默认设置下,Mathematica是在复数域中进行计算的,这会增加其操作的难度。但作者把包含复数系数的表达式视作“无效”。所以他们在使用Mathematica的时候将设置调整为实数域了?
我很好奇Mathematica是否可以解决该系统无法解决的问题。 30s的限制时间对于计算机代数系统有点武断了。
但总之,面对越来越机智的AI,已经有人发起了挑战赛,邀请AI挑战IMO金牌。
Facebook AI研究院出品 这篇论文有两位共同一作。 Guillaume Lample,来自法国布雷斯特,是Facebook AI研究院、皮埃尔和玛丽·居里大学在读博士。他曾于巴黎综合理工学院和CMU分别获得数学与计算机科学和人工智能硕士学位。 2014年进入Facebook实习。 Franois Charton,Facebook AI研究院的客座企业家(Visiting entrepreneur),主要研究方向是数学和因果关系。
传送门https://arxiv.org/abs/1912.01412 https://news.ycombinator.com/item?id=21084748
————
编辑 ∑Gemini
来源:新浪科技 参考技术D 第一问:角度减少30分,即减小整圆面积的1/720*π*100*100约等于13.9平方厘米
第二问:R增加1cm,即增加的面积等于现整圆面积-原整圆面积再*1/6=(π*101*101-π100*100)/6约等于105.2平方厘米
c语言访问内存冲突,这该怎么办啊
#include<stdio.h>
void main()
int score = 0, n = 0;
printf("Please input score:");
scanf_s("%d", score, sizeof(score));
if (score < 1 || score>100)printf("Please input again:");
n = score /10;
switch (n)
case 10:
case 9: printf("等级为A"); break;
case 8: printf("等级为B"); break;
case 7: printf("等级为C"); break;
case 6: printf("等级为D"); break;
default:printf("等级为E");
break;
提示:0x0F18E541 (msvcr120d.dll) (Project1.exe 中)处有未经处理的异常: 0xC0000005: 写入位置 0x00000000 时发生访问冲突。
栈:用来存放函数的形参和函数内的局部变量。由编译器分配空间,在函数执行完后由编译器自动释放。
堆:用来存放由动态分配函数(如malloc)分配的空间。是由程序员自己手动分配的,并且必须由程序员使用free释放。如果忘记用free释放,会导致所分配的空间一直占着不放,导致内存泄露。
全局局:用来存放全局变量和静态变量。存在于程序的整个运行期间,是由编译器分配和释放的。
文字常量区:例如char *c = “123456”;则”123456”为文字常量,存放于文字常量区。也由编译器控制分配和释放。
程序代码区:用来存放程序的二进制代码。
例子(一)
int a = 0; //全局区
void main()
int b; //栈
char s[] = abc; //s在栈,abc在文字常量区
char *p1,*p2; //栈
char *p3 = 123456; //123456在常量区,p3在栈上
static int c =0; //全局区
p1 = (char *)malloc(10); //p1在栈,分配的10字节在堆
p2 = (char *)malloc(20); //p2在栈,分配的20字节在堆
strcpy(p1, 123456); //123456放在常量区
例子(二)
//返回char型指针
char *f()
//s数组存放于栈上
char s[4] = '1','2','3','0';
return s; //返回s数组的地址,但程序运行完s数组就被释放了
void main()
char *s;
s = f();
printf (%s, s); //打印出来乱码。因为s所指向地址已经没有数据
2、动态分配释放内存
用malloc动态分配内存后一定要判断一下分配是否成功,判断指针的值是否为NULL。
内存分配成功后要对内存单元进行初始化。
内存分配成功且初始化后使用时别越界了。
内存使用完后要用free(p)释放,注意,释放后,p的值是不会变的,仍然是一个地址值,仍然指向那块内存区,只是这块内存区的值变成垃圾了。为了防止后面继续使用这块内存,应在free(p)后,立即p=NULL,这样后面如果要使用,判断p是否为NULL时就会判断出来。
NO.1
void GetMemory(char *p)
p = (char *)malloc(100);
void Test(void)
char *str = NULL;
GetMemory(str);
strcpy(str,hello world);
printf(str);
请问运行Test函数后会是什么样的结果?
NO.2
char *GetMemory(void)
char p[] = hello world;
retrun p;
void Test(void)
char *str = NULL;
str = GetMemory();
printf(str);
问题同NO.1
NO.3
void GetMemory2(char **p, int num)
*p = (char *)malloc(num);
void Test(void)
char *str = NULL;
GetMemory(&str,100);
strcpy(str,hello);
printf(str);
问题同NO.1
NO.4
void Test(void)
char *str = (char *)malloc(100);
strcpy(str,hello);
free(str);
if(str != NULL)
strcpy(str,world);
printf(str);
问题同NO.1
我对以上问题的分析:
NO.1:程序首先申请一个char类型的指针str,并把str指向NULL(即str里存的是NULL的地址,*str为NULL中的值为0),调用函数的过程中做了如下动作:1申请一个char 类型的指针p,2把str的内容copy到了p里(这是参数传递过程中系统所做的),3为p指针申请了100个空间,4返回Test函数.最后程序把字符串hello world拷贝到str指向的内存空间里.到这里错误出现了!str的空间始终为NULL而并没有实际的空间.深刻理解函数调用的第2步,将不难发现问题所在!(建议:画图理解)
NO.2:程序首先申请一个char类型的指针str,并把str指向NULL.调用函数的过程中做了如下动作:1申请一数组p[]并将其赋值为hello world(数组的空间大小为12),2返回数组名p付给str指针(即返回了数组的首地址).那么这样就可以打印出字符串"hello world"了么?当然是不能的!因为在函数调用的时候漏掉了最后一步.也就是在第2步return数组名后,函数调用还要进行一步操作,也就是释放内存空间.当一个函数被调用结束后它会释放掉它里面所有的变量所占用的空间.所以数组空间被释放掉了,也就是说str所指向的内容将不确定是什么东西.
NO.3:正确答案为可以打印出hello.但内存泄漏了!
NO.4:申请空间,拷贝字符串,释放空间.前三步操作都没有任何问题.到if语句里的判断条件开始出错了,因为一个指针被释放之后其内容并不是NULL,而是一个不确定的值.所以if语句永远都不能被执行.这也是著名的"野"指针问题.所以我们在编写程序释放一个指针之后一定要人为的将指针付成NULL.这样就会避免出现"野"指针的出现.有人说"野"指针很可怕,会带来意想不到的错误.
C语言内存对齐
C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。
使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
还是让我们来看看例子。
示例1:
struct BF1
char f1 : 3;
char f2 : 4;
char f3 : 5;
;
其内存布局为:
|_f1__|__f2__|_|____f3___|____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
0 3 7 8 1316
位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2。
示例2:
struct BF2
char f1 : 3;
short f2 : 4;
char f3 : 5;
;
由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。
示例3:
struct BF3
char f1 : 3;
char f2;
char f3 : 5;
;
什么是内存对齐
考虑下面的结构:
struct foo
char c1;
short s;
char c2;
int i;
;
假设这个结构的成员在内存中是紧凑排列的,假设c1的地址是0,那么s的地址就应该是1,c2的地址就是3,i的地址就是4。也就是
c1 00000000, s 00000001, c2 00000003, i 00000004。
可是,我们在Visual c/c++ 6中写一个简单的程序:
struct foo a;
printf("c1 %p, s %p, c2 %p, i %p/n",
(unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
运行,输出:
c1 00000000, s 00000002, c2 00000004, i 00000008。
为什么会这样?这就是内存对齐而导致的问题。
为什么会有内存对齐
以下内容节选自《Intel Architecture 32 Manual》。
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。
编译器对内存对齐的处理
缺省情况下,c/c++编译器默认将结构、栈中的成员数据进行内存对齐。因此,上面的程序输出就变成了:
c1 00000000, s 00000002, c2 00000004, i 00000008。
编译器将未对齐的成员向后移,将每一个都成员对齐到自然边界上,从而也导致了整个结构的尺寸变大。尽管会牺牲一点空间(成员之间有空洞),但提高了性能。
也正是这个原因,我们不可以断言sizeof(foo) == 8。在这个例子中,sizeof(foo) == 12。
如何避免内存对齐的影响
那么,能不能既达到提高性能的目的,又能节约一点空间呢?有一点小技巧可以使用。比如我们可以将上面的结构改成:
struct bar
char c1;
char c2;
short s;
int i;
;
这样一来,每个成员都对齐在其自然边界上,从而避免了编译器自动对齐。在这个例子中,sizeof(bar) == 8。
这个技巧有一个重要的作用,尤其是这个结构作为API的一部分提供给第三方开发使用的时候。第三方开发者可能将编译器的默认对齐选项改变,从而造成这个结构在你的发行的DLL中使用某种对齐方式,而在第三方开发者哪里却使用另外一种对齐方式。这将会导致重大问题。
比如,foo结构,我们的DLL使用默认对齐选项,对齐为
c1 00000000, s 00000002, c2 00000004, i 00000008,同时sizeof(foo) == 12。
而第三方将对齐选项关闭,导致
c1 00000000, s 00000001, c2 00000003, i 00000004,同时sizeof(foo) == 8。
如何使用c/c++中的对齐选项
vc6中的编译选项有 /Zp[1|2|4|8|16] ,/Zp1表示以1字节边界对齐,相应的,/Zpn表示以n字节边界对齐。n字节边界对齐的意思是说,一个成员的地址必须安排在成员的尺寸的整数倍地址上或者是n的整数倍地址上,取它们中的最小值。也就是:
min ( sizeof ( member ), n)
实际上,1字节边界对齐也就表示了结构成员之间没有空洞。
/Zpn选项是应用于整个工程的,影响所有的参与编译的结构。
要使用这个选项,可以在vc6中打开工程属性页,c/c++页,选择Code Generation分类,在Struct member alignment可以选择。
要专门针对某些结构定义使用对齐选项,可以使用#pragma pack编译指令。指令语法如下:
#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )
意义和/Zpn选项相同。比如:
#pragma pack(1)
struct foo_pack
char c1;
short s;
char c2;
int i;
;
#pragma pack()
栈内存对齐
我们可以观察到,在vc6中栈的对齐方式不受结构成员对齐选项的影响。(本来就是两码事)。它总是保持对齐,而且对齐在4字节边界上。
验证代码
#include <stdio.h>
struct foo
char c1;
short s;
char c2;
int i;
;
struct bar
char c1;
char c2;
short s;
int i;
;
#pragma pack(1)
struct foo_pack
char c1;
short s;
char c2;
int i;
;
#pragma pack()
int main(int argc, char* argv[])
char c1;
short s;
char c2;
int i;
struct foo a;
struct bar b;
struct foo_pack p;
printf("stack c1 %p, s %p, c2 %p, i %p/n",
(unsigned int)(void*)&c1 - (unsigned int)(void*)&i,
(unsigned int)(void*)&s - (unsigned int)(void*)&i,
(unsigned int)(void*)&c2 - (unsigned int)(void*)&i,
(unsigned int)(void*)&i - (unsigned int)(void*)&i);
printf("struct foo c1 %p, s %p, c2 %p, i %p/n",
(unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
printf("struct bar c1 %p, c2 %p, s %p, i %p/n",
(unsigned int)(void*)&b.c1 - (unsigned int)(void*)&b,
(unsigned int)(void*)&b.c2 - (unsigned int)(void*)&b,
(unsigned int)(void*)&b.s - (unsigned int)(void*)&b,
(unsigned int)(void*)&b.i - (unsigned int)(void*)&b);
printf("struct foo_pack c1 %p, s %p, c2 %p, i %p/n",
(unsigned int)(void*)&p.c1 - (unsigned int)(void*)&p,
(unsigned int)(void*)&p.s - (unsigned int)(void*)&p,
(unsigned int)(void*)&p.c2 - (unsigned int)(void*)&p,
(unsigned int)(void*)&p.i - (unsigned int)(void*)&p);
printf("sizeof foo is %d/n", sizeof(foo));
printf("sizeof bar is %d/n", sizeof(bar));
printf("sizeof foo_pack is %d/n", sizeof(foo_pack));
return 0;
参考技术A 什么东西都是二进制存放在内存里的
char 占一个字节,就是八个01组成的值追问
可是为什么上面的代码运行不了呢
参考技术B scanf_s("%d", score, sizeof(score)); 这条语句少了取地址符&scanf_s("%d", &score, sizeof(score));
以上是关于这该怎么做?高数求解的主要内容,如果未能解决你的问题,请参考以下文章