guocong89 发表于 2011-1-10 21:51:58

发现一个Trick,请来分析分析原理

进行如下替换操作a - b + (a - b) c /. a - b -> x


结果是
(a - b) c + x


按照帮助 Applying Transformation Rules 条目的介绍,
The replacement expr/.rules tries each rule just once on each part of expr.


要想进行 重复迭代替换,需要这么做
a - b + (a - b) c //. a - b -> x


但问题来了,如下过程,
a + a b /. a -> x

倒是把a给全部替换掉了

那么这两个之间有什么本质区别呢?

我理解 /. 不进行迭代替换是为了避免这种情形

log /. log -> log + log


但我觉得最早那个表达式中,两个 a-b 是完全独立的,应该在第一次扫描是就匹配上的,所以应该都替换掉才合理,第二个 a-b 并不是在第一次替换的基础上生成的。

大家有什么看法呢?

ggggwhw 发表于 2011-1-10 22:17:52

本帖最后由 ggggwhw 于 2011-1-10 22:18 编辑

In:= (a + b - c) + (a - c) /. a - c -> x

Out= 2 a + b - 2 cIn:= (a + b - c) + (a - 2 c)*d /. a - c -> x

Out= b + (a - 2 c) d + xIn:= (a + b - c) + (a - c)*d /. a - c -> x

Out= b + (a - c) d + x
In:= (a + b - c) + (a - c) /. a - c -> x

Out= 2 a + b - 2 c
可见在替换之前,mathematica 应该是先进行了一些运算的.

guocong89 发表于 2011-1-10 22:27:40

2# ggggwhw
第三例中 a-c 分明被保留着且应该匹配

ggggwhw 发表于 2011-1-11 10:30:58

上面几例的形式类似但是他们的FullForm形式却能看出差别.
mathematica 会将你输入的表达式先改写成FullForm的形式,然后再进行替换,In:= (a b)^2 /. a b -> x

Out= a^2 b^2In:= (a b)^2 /. a^2 b^2 -> x

Out= x比如(ab)^2,
写成FullForm形式后,没有了小括号的概念,但是个有了复合函数的概念,在复合函数中逗号前后的多个量之间的关系是并列的,没有先后顺序.但是复合函数中的中括号决定了各个函数的优先级不同,
复合函数可以写成如下形式:
0,2,2,2,2],1],1,1,1,1]
其中0,1,2,3都表示第n层的复合函数字头,
/.a-b->x就是
第一步,看0[]是否和Plus]相同,若相同则替换,结束,若不相同,则进入下一步,
第二步,看多个1[]中是否有Plus],若有则替换,结束,若没有,则进入下一步,
第三步,看多个2[]中是否有Plus],若有则替换,结束,若没有,则进入下一步,
第四步,看多个3[]中是否有Plus],若有则替换,结束,若没有,则不替换,结束.
注意,在替换过程中,遇见了Plus],Plus,d],Plus],都会替换其中的Plus]的,但是遇见了Plus],Plus ,Times[-2, b] ],系统却无法识别.

guocong89 发表于 2011-1-11 12:05:02

本帖最后由 guocong89 于 2011-1-11 12:08 编辑

4# ggggwhw
那也就是说,/. 替换 是按照 语法树解析深度 执行的?

如果在一层上替换了,就不再进入下一层进行替换?a - b + (a - b) c // TreeForm


在第一层中匹配了 Plus那么第三层的就不再继续执行匹配替换了?

那么对于如下这个式子Hold // TreeForm执行替换Hold /. a -> x确实把所有层次的a都替换掉了。

这又怎么理解呢?

ggggwhw 发表于 2011-1-11 17:22:25

那么我想,mathematica 对待表达式和单个变量在替换时采取的是两种原则.
对于单个变量一次就替换完了,对于表达式一次替换一层.

guocong89 发表于 2011-1-11 18:15:18

本帖最后由 guocong89 于 2011-1-11 18:18 编辑

更诡异的是比较一下下面几个式子a^2 - Sin /. a^2 -> x
a b - Sin /. a b -> x
a/b - Sin /. a/b -> x
a + b - Sin /. a + b -> x
a - b - Sin /. a - b -> x从Attributes[{Plus, Times}]看不出来什么本质差别

最后这个测试也许能够说明点什么a b + Sin /. a b -> x
a b Sin /. a b -> x
(a + b) Sin /. a + b -> x
(a + b) + Sin /. a + b -> x输出x + Sin
x Sin
x Sin
x + Sin

ggggwhw 发表于 2011-1-11 22:25:59

也就是说mathematica 只认为在FullForm形式中,Times和Plus为一个层次,对于向Sin,Log,Power等复合函数所对应的层视而不见.

HyperGroups 发表于 2011-1-12 16:37:08

按深度替换,
Level
={}
exp/.a-b->sdfasdf
{}里面有几个a-b就替换几个a-b

guocong89 发表于 2011-1-12 17:49:31

9# HyperGroups

不对吧。。。

Level
a - b + (a - b) c + (a - b) d /. a - b -> x
输出
{a, -1, b, -b, a, -1, b, -b, a - b, c, (a - b) c, a, -1, b, -b,a - b, d, (a - b) d}(a - b) c + (a - b) d + x



恰恰相反,出现的a-b并没有替换,而是没有出现的被替换了

原因也可以理解。

Level是按照 Deep-First-Search 策略进行搜索的,返回表达式树的 按照 DFS 策略周游时 某个(或某些)深度层次上的子表达式。Level 和前面帖子里提到的 层 同一个概念。

所以 我就感觉很奇怪,a-b 明明就是 表达式的一个子树,为什么没有被替换呢?相反的,它按照Plus的flat特性,把本不是它的子树的 “首层a-b” 给替换掉了,所以感觉不符合逻辑,应该被修改掉。

HyperGroups 发表于 2011-1-12 17:58:40

突然发现刚刚的想法好弱智啊

本帖最后由 HyperGroups 于 2011-1-12 18:20 编辑

10# guocong89

是嘛,看来还要再想想,刚好像测试了几个例子成功了嘛,哈哈

刚才的说法的确是愚蠢了,只是一个小范围的巧合

Level里就没有a-b
当然a-b/.a-b->x是能被替换的。

HyperGroups 发表于 2011-1-12 18:26:11

本帖最后由 HyperGroups 于 2011-1-12 18:29 编辑

。。。我在胡说八道了。。。呵呵,吃饭先。

guocong89 发表于 2011-1-12 18:29:47

12# HyperGroups
第0层就是表达式自己啊。。。

HyperGroups 发表于 2011-1-12 18:30:42

13# guocong89

回复这么快,哈哈,吃饭了先,晚上好好看看。

HyperGroups 发表于 2011-1-12 20:06:24

本帖最后由 HyperGroups 于 2011-1-12 21:08 编辑

一楼中
a - b + (a - b) c /. a - b -> x
这里第一个a-b 和 第二个 a-b似乎是不同的,之所以能替换到第一个是因为Plus的Flat属性,如果去掉这个属性,则替换后变成 a-b+xc,

a + a b /. a -> x 因为两个a同时被搜索到了,因此同时替换,替换一次,看起来像是替换了多次

guocong89 发表于 2011-1-12 20:16:21

15# HyperGroups
第一个替换没有什么疑问,我奇怪的是为什么第二个不替换。

HyperGroups 发表于 2011-1-12 20:24:52

现在回过头来看你10楼给出的反例。
Level
事实上Level是不会出现a-b的,如果把Plus的Flat属性去除,那么
a - b + (a - b) c /. a - b -> x
第一个a-b就不会被替换,
同样
a - b + (a - b) c + (a - b) d /. a - b -> x
第一个a-b就不会被替换,而第二个第三个a-b则被全部替换成
a-b+c x+ d x

因为Flat属性的影响。

HyperGroups 发表于 2011-1-12 21:31:08

16# guocong89

问题: a - b + (a - b) c + (a - b) d /. a - b -> x为什么只替换了第一个a - b到x?
这是符合ReplaceAll的函数说明的,只替换了一次就不再进行替换了。
但是为什么 {a, b, a, d, {{a}}} /.
a -> x就替换了一次但是两个a都替换成x了呢?首先肯定是做了一次替换,只是一下子在同一层Level[
   expr, -1] 里找到两个匹配项。
第二个和第三个没被替换是因为第一个被替换了后按ReplaceAll的规则当然就不替换了,因为第二个和第三个还没有被找到。而去除Flat属性后\
就直接找到了后面的两个a - b,替换的效果就跟常量一样了。{a, b, c, a} /. a -> x
在5楼中的例子
Level, -1] 中出现的三个a也是这样被同时替换的。

而如果没有Flat属性,因为FullForm的形式就无法识别第一个a-b了,因此mathematica应该是首先识别这个,如果继续替换就没有了这种情况就继续搜索,

guocong89 发表于 2011-1-12 21:49:36

什么叫做 同时替换? 为什么可以同时找到a 却不能同时找到 a-b ?

更诡异的是7楼的最后几个测试。

这个测试表现出来的行为是,Plus与Times混合,Plus或者Times的匹配会完全被发现,如果是连加或者连乘,内层的匹配就失效了。

guocong89 发表于 2011-1-12 21:52:51

测试继续
Hold] /. a - b -> x
Hold[(a - b) (a - b) Sin] /. a - b -> x
Hold[(a - b + c) Sin] /. a - b -> x
Hold] /. a - b -> x
输出结果Hold + x]
Hold]
Hold[(c + x) Sin]
Hold + x]
页: [1] 2
查看完整版本: 发现一个Trick,请来分析分析原理