如何修正我的幂律简化函数(使结果更易于阅读),使之适用于Racket中的符号微分函数?

如何修正我的幂律简化函数(使结果更易于阅读),使之适用于Racket中的符号微分函数?,racket,symbolic-math,simplification,Racket,Symbolic Math,Simplification,这是我正确工作的微分函数 #lang racket (define (diff x expr) (if (not (list? expr)) (if (equal? x expr) 1 0) (let ( (operation (car expr)) (u (cadr expr)) (v (caddr expr))) (case operation ((+) (list '+ (diff x u)

这是我正确工作的微分函数

#lang racket

(define (diff x expr) 
  (if (not (list? expr))
      (if (equal? x expr) 1 0) 
  (let ( (operation (car expr)) 
         (u (cadr expr))
         (v (caddr expr)))
       (case operation
          ((+) (list '+ (diff x u) (diff x v))) 
          ((-) (list '- (diff x u) (diff x v))) 
          ((*) (list '+                             
                     (list '* u (diff x v))
                     (list '* v (diff x u))))       
          ((/) (list '/ (list '- (list '* v (diff x u)) (list '* u (diff x v))) 
                     (list '* v v)))                
          ((^) (list '* v (list '* (list '^ u (- v 1)) (diff x u ))))                           
))))
现在我也有了大部分的简化功能,但在某个地方有一个问题,我想这是在我的幂律简化器中

(define(simplify expr)
  (if (not (list? expr)) expr
  (let ((operation (car expr))      
       (a (simplify (cadr expr)))   
       (b (simplify (caddr expr)))) 
   (case operation 
        ((+) (if (and (number? a)(= a 0)) b    
                 (if (number? b) (if (= b 0) a 
                                     (+ a b)) 
                 (list operation a b)))) 

        ((-) (if (and (number? a) (= a 0)) (- b)         
                 (if (number? b) (if (= b 0) a  
                                     (- a b))
                 (list operation a b)))) 

        ((*) (cond [(number? a)
                    (cond [(= 1 a) b]
                          [(= 0 a) 0]
                          [else (if (number? b)
                                    (cond [(= b 1) a]
                                          [(= b 0) 0]
                                          [else (* a b)])
                                    (list operation a b))])]
                   [(and (number? b) (= b 0)) 0]
                   [(list operation a b)]))
;The case a/b where b=1 is currently only simplified if a is number. Insert an extra case into the cond expression handling b=1
        ((/) (cond [(number? a)
                    (cond [(= 1 b) a]
                          [(= 0 a) 0]
                          [else (if (number? b)
                                    (cond [(= b 1) a]
                                          [(= b 0) 0]
                                          [else (/ a b)])
                                    (list operation a b))])]
                   [(and (number? b) (= b 0)) 0]; this is where an error should be thrown
                         (cond [(= b 1) 1]
                   [(list operation a b)]))

       ((^) (cond [(number? a)
                   ;if a is 1, 1^x is always 1
                   (cond [(= a 1) 1]
                         [else (if (number? b)
                                   ;if a and b are 0 throw error else anything ^0 is 1.
                                   (cond [(= b 0) (if (= a 0) (error "A and B are both 0, statement undefined!") 1)]
                                         ;if b is 1, x^1 is always x
                                         [(= b 1) a]
                                         ;else a^b
                                         [(expt a b)])
                                   ;a or b are continuations
                                   (list operation a b))])]                                  
                   [else (list operation a b)]))
 ))))
我做了很多测试,大多数都通过了,但也有一些没有通过,我不知道为什么

(simplify '(/ x 1)) ;why is this not working correctly
(simplify '(+ (* (^ x 5) 0) (* 3 (* 5 (* (^ x 4) 1)))) ;not simplifying correctly
(simplify '(* 3 (* (^ x 2) 1))) ;not simplifying correctly
;(simplify '(/ 1 0));not working 
;(simplify '(^ 0 0));this works fine just returns an exception

较短的解决方案

(define (simplify expr)
  (if (not (list? expr))
      expr
      (let ((operation (car expr))
            (a (cadr expr))
            (b (caddr expr)))
        (case operation
          ((+) (cond ((and (number? a) (number? b))
                      (cond ((zero? a) b)
                            ((zero? b) a)
                            (else (+ a b))))
                     (else (list operation (simplify a) (simplify b)))))
          ((-) (cond ((and (number? a) (number? b))
                      (cond ((zero? a) (- b))
                            ((zero? b) a)
                            (else (- a b))))
                     (else (list operation (simplify a) (simplify b)))))
          ((*) (cond ((and (number? a) (number? b))
                      (cond ((or (zero? a) (zero? b)) 0)
                            ((= a 1) b)
                            ((= b 1) a)
                            (else (* a b))))
                     ((number? a)
                      (cond ((zero? a) 0)
                            ((= a 1) (simplify b))
                            (else (list operation (simplify a) (simplify b)))))
                     ((number? b)
                      (cond ((zero? b) 0)
                            ((= b 1) (simplify a))
                            (else (list operation (simplify a)(simplify b)))))
                     (else (list operation (simplify a) (simplify b)))))
          ((/) (cond ((and (number? a) (number? b))
                      (cond ((zero? b) (error "Divison by 0, statement undefined!"))
                            ((zero? a) 0)
                            ((= b 1) a)
                            (else (/ a b))))
                     ((number? a)
                      (cond ((zero? a) 0)
                            (else (list operation (simplify a) (simplify b)))))
                     ((number? b)
                      (cond ((zero? b) (error "Divison by 0, statement undefined!"))
                            ((= b 1) (simplify a))
                            (else (list operation (simplify a) (simplify b)))))
                     (else
                      (list operation (simplify a) (simplify b)))))
          ((^) (cond ((and (number? a) (number? b))
                      (cond ((and (zero? a) (zero? b)) (error "A and B are both 0, statement undefined!"))
                            ((zero? a) (if (< b 0)
                                           (error "Exponent undefined for 0 and negative B.")
                                           0))
                            ((zero? b) 1)
                            ((= a 1) 1)
                            ((= b 1) a)
                            (else (expt a b))))
                     ((number? a)
                      (cond ((zero? a) 0) ;; depends on b actually - if b < 0 then undefined
                            ((= a 1) 1)
                            (else (list operation (simplify a) (simplify b)))))
                     ((number? b)
                      (cond ((zero? b) 1) ;; depends on a actually - if a = 0 then undefined
                            ((= b 1) (simplify a))
                            (else (list operation (simplify a) (simplify b)))))
                     (else (list operation (simplify a) (simplify b)))))))))
(define (simplify expr)
  (if (not (list? expr))
      expr
      (let ((operation (car expr))
            (a (simplify (cadr expr)))
            (b (simplify (caddr expr))))
        (case operation
          ((+) (cond ((and (number? a) (= a 0)) b)
                     ((and (number? b) (= b 0)) a)
                     ((and (number? b) (number? a)) (+ a b))
                     (else (list operation (simplify a) (simplify b)))))
          ((-) (cond ((and (number? a) (= a 0)) (- b))
                     ((and (number? b) (= b 0)) a)     
                     ((and (number? a) (number? b)) (- a b))
                     (else (list operation (simplify a) (simplify b)))))
          ((*) (cond ((and (number? a) (= a 1)) b)
                     ((and (number? a) (= a 0)) 0)
                     ((and (number? a) (number? b) (= b 1)) a)
                     ((and (number? a) (number? b) (= b 0)) 0)
                     ((and (number? a) (number? b)) (* a b))
                     ((and (number? b) (= b 1)) a)               ;; added by me
                     ((and (number? b) (= b 0)) 0)
                     (else (list operation (simplify a) (simplify b)))))
          ((/) (cond ((and (number? a) (= a 0)) 0)
                     ((and (number? a) (number? b) (= b 1)) a)
                     ((and (number? a) (number? b) (= b 0)) (error "Divison by 0, statement undefined!")) ;; error added
                     ((and (number? a) (number? b)) (/ a b))
                     ((and (number? b) (= b 1)) a)               ;; added by me
                     ((and (number? b) (= b 0)) (error "Divison by 0, statement undefined!")) ;; error added
                     (else (list operation (simplify a) (simplify b)))))
          ((^) (cond ((and (number? a) (= a 1)) 1)
                     ((and (number? a) (number? b) (= a 0) (= b 0)) (error "A and B are both 0, statement undefined!"))
                     ((and (number? a) (number? b) (= b 0)) 1)
                     ((and (number? a) (number? b) (= b 1)) a)
                     ((and (number? a) (number? b)) (expt a b))
                     ((and (number? b) (= b 1)) a)               ;; added by me
                     ((and (number? b) (= b 0)) 1)               ;; corrected to 1 (before: zero)
                     (else (list operation (simplify a) (simplify b)))))))))
通过使用Racket固有的计算数字的能力(并执行正确的错误消息传递,例如除以零错误)

带有条件
(and(number?a)(number?b))
的第一个子句涵盖了两个操作数都是数字的情况。这种情况很容易处理,因为Racket“知道”如何处理基本的数学运算。因此,您只需计算该值并将其作为简化返回(因此:
(ab)
作为返回值)。 注意:在
/
的情况下,如果b为零,则必须引发
除以零的错误。但是Racket会自动提升它,如果我们给
b的值为零,
,那么这里我们让Racket也做错误提升,让它返回并计算Racket
(/ab)

第二个子句是
a
是一个数字的情况。 由于第一次测试肯定失败,我们现在可以肯定地知道,
a
b
中至少有一个是由形式或符号组成的,而不是数字。如果这个条件为真,我们知道
a
是一个数字,但b必须是组合的。(如果
b
是一个数字,则第一个条件将为true…)。 作为说明,我们还有一个带子句的
cond
。 这些条款以数字形式处理
a
的特殊情况。 加法
+
和减法
-
都是对
0
不变的,因此这里对这两个分支的第一个检查是
a
是否为零
(零?a)
。在这种情况下,我们省略运算符和
a=0
,只返回
b
。但是由于
b
确实是一种组合形式,我们在其上调用
simplify
,以递归地简化
b
(否则,表达式b将按原样给出,而无需进一步简化)。 如果
a
不是零,我们就进入
else
子句,知道
a
是一个非零数字,
b
必须是一个组合形式。 因此,我们列出了操作符和
a
b
并对它们进行了简化。 实际上,
a
不需要进一步简化,因为我们知道,它是一个数字。您可以删除
simplify
调用
a
,只需编写
a
。 对于
*
/
我们区分了3种情况:

  • 如果
    *
    /
    a
    为零,则我们知道所有内容都变为零,因此我们在此时返回整个表达式的
    0
  • 然后,我们要求求
    *
    /
    的不变量,即
    1
    。因此,
    (=1A)
    ,因此我们在本例中返回
    (简化b)
    ,而不带
    a
    和运算符
对于第三个子句,
b
是一个数字,
a
组成,所有内容都与前一个子句相同-只是将
a
替换为处处
b
。只有一个例外:对于
/
而言,如果
b
为零,则必须给出
除以零的错误。因此,我们在这里通过
(error“division by 0,statement undefined!”)引发一个错误。
。因为
a
不是一个数字,我们不能让Racket在这里计算出任何东西,所以我们手动提出一个错误

第四个子句(
else
)只有在
a
b
各自组成时才会被调用,因为该路径中以前的所有测试都失败了。 在这种情况下,我们递归调用
(simplify a)
(simplify b)
,并将这些结果与操作符一起列为列表。因此,对于每个操作数,将应用此处描述的简化过程

重要:
a
b
的let绑定也对操作数调用
simplify
。如果我们在这里省略了
simplify
调用,简化将在一个级别后停止。因此,
simplify
调用-那些在
let
绑定中的调用-以及那些在
cond
末尾的调用-都是在整个表达式树中“拉”递归所必需的-正如我们前天看到的,当时我忘记了
cond
子句中的
simplify
)。因此,这两层
简化
调用就像马达一样将简化过程一直拉到底

解决方案

(define (simplify expr)
  (if (not (list? expr))
      expr
      (let ((operation (car expr))
            (a (cadr expr))
            (b (caddr expr)))
        (case operation
          ((+) (cond ((and (number? a) (number? b))
                      (cond ((zero? a) b)
                            ((zero? b) a)
                            (else (+ a b))))
                     (else (list operation (simplify a) (simplify b)))))
          ((-) (cond ((and (number? a) (number? b))
                      (cond ((zero? a) (- b))
                            ((zero? b) a)
                            (else (- a b))))
                     (else (list operation (simplify a) (simplify b)))))
          ((*) (cond ((and (number? a) (number? b))
                      (cond ((or (zero? a) (zero? b)) 0)
                            ((= a 1) b)
                            ((= b 1) a)
                            (else (* a b))))
                     ((number? a)
                      (cond ((zero? a) 0)
                            ((= a 1) (simplify b))
                            (else (list operation (simplify a) (simplify b)))))
                     ((number? b)
                      (cond ((zero? b) 0)
                            ((= b 1) (simplify a))
                            (else (list operation (simplify a)(simplify b)))))
                     (else (list operation (simplify a) (simplify b)))))
          ((/) (cond ((and (number? a) (number? b))
                      (cond ((zero? b) (error "Divison by 0, statement undefined!"))
                            ((zero? a) 0)
                            ((= b 1) a)
                            (else (/ a b))))
                     ((number? a)
                      (cond ((zero? a) 0)
                            (else (list operation (simplify a) (simplify b)))))
                     ((number? b)
                      (cond ((zero? b) (error "Divison by 0, statement undefined!"))
                            ((= b 1) (simplify a))
                            (else (list operation (simplify a) (simplify b)))))
                     (else
                      (list operation (simplify a) (simplify b)))))
          ((^) (cond ((and (number? a) (number? b))
                      (cond ((and (zero? a) (zero? b)) (error "A and B are both 0, statement undefined!"))
                            ((zero? a) (if (< b 0)
                                           (error "Exponent undefined for 0 and negative B.")
                                           0))
                            ((zero? b) 1)
                            ((= a 1) 1)
                            ((= b 1) a)
                            (else (expt a b))))
                     ((number? a)
                      (cond ((zero? a) 0) ;; depends on b actually - if b < 0 then undefined
                            ((= a 1) 1)
                            (else (list operation (simplify a) (simplify b)))))
                     ((number? b)
                      (cond ((zero? b) 1) ;; depends on a actually - if a = 0 then undefined
                            ((= b 1) (simplify a))
                            (else (list operation (simplify a) (simplify b)))))
                     (else (list operation (simplify a) (simplify b)))))))))
(define (simplify expr)
  (if (not (list? expr))
      expr
      (let ((operation (car expr))
            (a (simplify (cadr expr)))
            (b (simplify (caddr expr))))
        (case operation
          ((+) (cond ((and (number? a) (= a 0)) b)
                     ((and (number? b) (= b 0)) a)
                     ((and (number? b) (number? a)) (+ a b))
                     (else (list operation (simplify a) (simplify b)))))
          ((-) (cond ((and (number? a) (= a 0)) (- b))
                     ((and (number? b) (= b 0)) a)     
                     ((and (number? a) (number? b)) (- a b))
                     (else (list operation (simplify a) (simplify b)))))
          ((*) (cond ((and (number? a) (= a 1)) b)
                     ((and (number? a) (= a 0)) 0)
                     ((and (number? a) (number? b) (= b 1)) a)
                     ((and (number? a) (number? b) (= b 0)) 0)
                     ((and (number? a) (number? b)) (* a b))
                     ((and (number? b) (= b 1)) a)               ;; added by me
                     ((and (number? b) (= b 0)) 0)
                     (else (list operation (simplify a) (simplify b)))))
          ((/) (cond ((and (number? a) (= a 0)) 0)
                     ((and (number? a) (number? b) (= b 1)) a)
                     ((and (number? a) (number? b) (= b 0)) (error "Divison by 0, statement undefined!")) ;; error added
                     ((and (number? a) (number? b)) (/ a b))
                     ((and (number? b) (= b 1)) a)               ;; added by me
                     ((and (number? b) (= b 0)) (error "Divison by 0, statement undefined!")) ;; error added
                     (else (list operation (simplify a) (simplify b)))))
          ((^) (cond ((and (number? a) (= a 1)) 1)
                     ((and (number? a) (number? b) (= a 0) (= b 0)) (error "A and B are both 0, statement undefined!"))
                     ((and (number? a) (number? b) (= b 0)) 1)
                     ((and (number? a) (number? b) (= b 1)) a)
                     ((and (number? a) (number? b)) (expt a b))
                     ((and (number? b) (= b 1)) a)               ;; added by me
                     ((and (number? b) (= b 0)) 1)               ;; corrected to 1 (before: zero)
                     (else (list operation (simplify a) (simplify b)))))))))
这将正确地简化。 我以一种非常低效的方式写了它(结果是
cond
),所以-我将“简化”答案:D。我在添加的行中添加了注释。 它简化了
(简化“(+(*(^x 5)0)(*3(*5(*(^x 4)1()))
”(*3(*5(^x 4))
哪一个更好(诀窍是递归调用
else
子句中的每个操作数简化
)。

但是,我希望在结尾有
(*15(^x 4))
。为此,我们需要更多的检查…

您标记为工作不正常的表达式的预期结果值是多少?在
/
的情况下,
(数字?b)
,我不认为cond答案是正确的。当
b
等于
0
时,答案不是
0
,它是未定义的。标记的表达式当前返回什么?您在注释中有:
;/
;b是一个数字,b=1->a
,但我在您的代码中没有看到与之对应的大小写