Advertisement
Guest User

Super Simple Nanopass CAS

a guest
Dec 1st, 2017
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 8.85 KB | None | 0 0
  1. #lang racket
  2. (require parser-tools/lex
  3.          (prefix-in : parser-tools/lex-sre)
  4.          parser-tools/yacc
  5.          nanopass/base)
  6.  
  7. (define-tokens math [CNST VAR])
  8. (define-empty-tokens math/e [PLS MIN TIM LEFT RIGHT EQ END])
  9.  
  10. (define lex-math
  11.   (lexer
  12.    [(:+ whitespace) (lex-math input-port)]
  13.    [lower-case (token-VAR (string->symbol lexeme))]
  14.    [(:or "(" "[") 'LEFT]
  15.    [(:or ")" "]") 'RIGHT]
  16.    ["+" 'PLS] ["-" 'MIN] ["*" 'TIM] ["=" 'EQ]
  17.    [(:: (:+ numeric) (:? "." (:+ numeric)))
  18.     (token-CNST (string->number lexeme))]
  19.    [#\newline 'END]
  20.    [(eof) 'END]))
  21.  
  22. (define-syntax define-parse
  23.   (syntax-rules ()
  24.     [(_ name clause ...)
  25.      (define name
  26.        (let ([parse (parser clause ...)])
  27.          (λ (port)
  28.            (parse (λ () (lex-math port))))))]))
  29.  
  30. (define-parse parse-math
  31.   (tokens math math/e)
  32.   (start eqn)
  33.   (end END)
  34.   (error (λ _ (error "invalid equation")))
  35.   (grammar
  36.    (eqn
  37.     [(expr EQ expr) `(solve ,$1 ,$3)])
  38.    (expr
  39.     [(expr PLS term) `(op+ ,$1 ,$3)]
  40.     [(expr MIN term) `(op- ,$1 ,$3)]
  41.     [(term) $1])
  42.    (term
  43.     [(term TIM fact) `(op* ,$1 ,$3)]
  44.     [(term nn-fact) `(op* ,$1 ,$2)]
  45.     [(fact) $1])
  46.    (fact
  47.     [(MIN nn-fact) `(op~ ,$2)]
  48.     [(nn-fact) $1])
  49.    (nn-fact
  50.     [(CNST) $1]
  51.     [(VAR) $1]
  52.     [(LEFT expr RIGHT) $2])))
  53.  
  54.  
  55. ;-------
  56. (define-language Aorig
  57.   (terminals
  58.    (number [c])
  59.    (nonnegative-integer [n m])
  60.    (symbol [x y]))
  61.   (entry Solve)
  62.   (Arith (a)
  63.     c
  64.     x
  65.     (op+ a1 a2)
  66.     (op- a1 a2)
  67.     (op~ a)
  68.     (op* a1 a2))
  69.   (Solve (so)
  70.     (solve a1 a2)))
  71.  
  72. (define-parser parse-sexp Aorig)
  73.  
  74.  
  75. ;-------
  76. (define-language Aeqzero
  77.   (extends Aorig)
  78.   (Solve (so)
  79.     (- (solve a1 a2))
  80.     (+ (solve a))))
  81.  
  82. (define-pass rhs-zero : Aorig (ir) -> Aeqzero ()
  83.   (definitions)
  84.   (Solve : Solve (so) -> Solve ()
  85.     [(solve ,[a1] ,[a2]) `(solve (op- ,a1 ,a2))]))
  86.  
  87. ;-------
  88. (define-language Anosub
  89.   (extends Aeqzero)
  90.   (Arith (a)
  91.     (- (op- a1 a2))))
  92.  
  93. (define-pass remove-subtract : Aeqzero (ir) -> Anosub ()
  94.   (definitions)
  95.   (Arith : Arith (a) -> Arith ()
  96.     [(op- ,[a1*] ,[a2*]) `(op+ ,a1* (op~ ,a2*))]))
  97.  
  98. ;-------
  99. (define-language Anoneg
  100.   (extends Anosub)
  101.   (Arith (a)
  102.     (- (op~ a))))
  103.  
  104. (define-pass remove-negate : Anosub (ir) -> Anoneg ()
  105.   (definitions)
  106.   (Arith : Arith (a) -> Arith ()
  107.     [(op~ ,[a*]) `(op* -1 ,a*)]))
  108.  
  109. ;-------
  110. (define-language Atiered
  111.   (extends Anoneg)
  112.   (Factor (f)
  113.     (+ c x))
  114.   (Term (t)
  115.     (+ (op* t1 t2) f))
  116.   (Arith (a)
  117.     (- c x)
  118.     (- (op* a1 a2))
  119.     (+ t)))
  120.  
  121. (define-pass distribute : Anoneg (ir) -> Atiered ()
  122.   (definitions
  123.     (define (mult lh rh)
  124.       (nanopass-case (Atiered Arith) lh
  125.         [(op+ ,a1 ,a2)
  126.          (with-output-language (Atiered Arith)
  127.            `(op+ ,(mult a1 rh) ,(mult a2 rh)))]
  128.         [,t
  129.          (nanopass-case (Atiered Arith) rh
  130.            [(op+ ,a1 ,a2) (mult rh lh)]
  131.            [,t2
  132.             (with-output-language (Atiered Term)
  133.               `(op* ,t ,t2))])])))
  134.   (Arith : Arith (a) -> Arith ()
  135.     [,c c]
  136.     [,x x]
  137.     [(op* ,[a1*] ,[a2*]) (mult a1* a2*)]))
  138.  
  139. ;--------
  140. (define-language Atiered*
  141.   (extends Atiered)
  142.   (Term (t)
  143.     (- (op* t1 t2) f)
  144.     (+ (prod f ...)))
  145.   (Arith (a)
  146.     (- (op+ a1 a2) t)
  147.     (+ (sum t ...))))
  148.  
  149. (define-pass flat-trees : Atiered (ir) -> Atiered* ()
  150.   (definitions
  151.     (define (factors t)
  152.       (nanopass-case (Atiered* Term) t
  153.         [(prod ,f^ ...) f^]))
  154.     (define (terms a)
  155.       (nanopass-case (Atiered* Arith) a
  156.         [(sum ,t^ ...) t^])))
  157.   (Factor : Factor (f) -> Factor ())
  158.   (Term : Term (t) -> Term ()
  159.     [,f
  160.      `(prod ,(Factor f))]
  161.     [(op* ,[t1*] ,[t2*])
  162.      `(prod ,(append (factors t1*) (factors t2*)) ...)])
  163.   (Arith : Arith (a) -> Arith ()
  164.     [,t
  165.      `(sum ,(Term t))]
  166.     [(op+ ,[a1*] ,[a2*])
  167.      `(sum ,(append (terms a1*) (terms a2*)) ...)]))
  168.  
  169. ;--------
  170. (define-language Aexpts
  171.   (extends Atiered*)
  172.   (Term (t)
  173.     (- (prod f ...))
  174.     (+ (c [x n] ...))))
  175.  
  176. (define-pass simplify-terms : Atiered* (ir) -> Aexpts ()
  177.   (definitions)
  178.   (Term : Term (t) -> Term ()
  179.     [(prod ,f^ ...)
  180.      (let ([vars (make-hash)]
  181.            [constant 1])
  182.        (for ([f (in-list f^)])
  183.          (nanopass-case (Atiered* Factor) f
  184.            [,x (hash-update! vars x add1 0)]
  185.            [,c (set! constant (* c constant))]))
  186.        (let ([vars+ (sort (hash->list vars)
  187.                           symbol<?
  188.                           #:key car)])
  189.          `(,constant [,(map car vars+) ,(map cdr vars+)] ...)))]))
  190.  
  191. (define-pass merge-terms : Aexpts (ir) -> Aexpts ()
  192.   (definitions)
  193.   (EqvC : Term (t) -> * ()
  194.     [(,c [,x ,n] ...) (list x n)])
  195.   (Arith : Arith (a) -> Arith ()
  196.     [(sum ,t^ ...)
  197.      `(sum ,(for/list ([g (in-list (group-by EqvC t^))])
  198.               (define-values [c x n]
  199.                 (for/fold ([c0 0] [x #f] [n #f])
  200.                           ([t (in-list g)])
  201.                   (nanopass-case (Aexpts Term) t
  202.                     [(,c [,x ,n] ...) (values (+ c c0) x n)])))
  203.               (with-output-language (Aexpts Term)
  204.                 `(,c [,x ,n] ...)))
  205.            ...)]))
  206.  
  207. (define-pass remove-zeros : Aexpts (ir) -> Aexpts ()
  208.   (definitions)
  209.   (Keep? : Term (t) -> * ()
  210.     [(,c [,x ,n] ...) (not (zero? c))])
  211.   (Arith : Arith (a) -> Arith ()
  212.     [(sum ,t^ ...) `(sum ,(filter Keep? t^) ...)]))
  213.  
  214. ;--------
  215. (define-language Aone-var
  216.   (extends Aexpts)
  217.   (Term (t)
  218.     (- (c [x n] ...))
  219.     (+ (c n)))
  220.   (Solve (so)
  221.     (- (solve a))
  222.     (+ (solve x a))))
  223.  
  224. (define-pass one-variable : Aexpts (ir) -> Aone-var ()
  225.   (definitions)
  226.   (Term : Term (a var) -> Term ()
  227.     [(,c [,x^ ,n^] ...)
  228.      (define n
  229.        (for/fold ([n 0])
  230.                  ([x (in-list x^)]
  231.                   [n (in-list n^)])
  232.          (cond
  233.            [(not (unbox var)) (set-box! var x) n]
  234.            [(equal? (unbox var) x) n]
  235.            [else (error "multi-variable equations unsupported")])))
  236.      `(,c ,n)])
  237.   (Arith : Arith (a var) -> Arith ()
  238.     [(sum ,[t* var -> t*] ...) `(sum ,t* ...)])
  239.   (Solve : Solve (so [var (box #f)]) -> Solve ()
  240.     [(solve ,[a* var -> a*])
  241.      (cond
  242.        [(not (unbox var)) (error "no variables found to solve")]
  243.        [else `(solve ,(unbox var) ,a*)])]))
  244.  
  245. ;--------
  246. (define-language Apolynomial
  247.   (extends Aone-var)
  248.   (Term (t) (- (c n)))
  249.   (Arith (a) (- (sum t ...)))
  250.   (Solve (so)
  251.     (- (solve x a))
  252.     (+ (solve-poly x [c ...]))))
  253.  
  254. (define-pass polynomial : Aone-var (ir) -> Apolynomial ()
  255.   (definitions)
  256.   (Coef : Term (so) -> * ()
  257.     [(,c ,n) (values n c)])
  258.   (Solve : Solve (so) -> Solve ()
  259.     [(solve ,x (sum ,t^ ...))
  260.      (define coefs
  261.        (for/hash ([t (in-list t^)])
  262.          (Coef t)))
  263.      (define degree
  264.        (apply max (hash-keys coefs)))
  265.      (define (coef i)
  266.        (hash-ref coefs i 0))
  267.      `(solve-poly ,x [,(map coef (range (add1 degree))) ...])]))
  268.  
  269. ;--------
  270. (define-language Asolution
  271.   (extends Apolynomial)
  272.   (Solve (so)
  273.     (- (solve-poly x [c ...]))
  274.     (+ (solutions [x c] ...))))
  275.  
  276. (define-pass solve : Apolynomial (ir) -> Asolution ()
  277.   (Solve : Solve (so) -> Solve ()
  278.     [(solve-poly ,x [,c0]) `(solutions)]
  279.     [(solve-poly ,x [,c0 ,c1])
  280.      ; a + bx = 0
  281.      ; x = -a / b
  282.      `(solutions [,x ,(/ (- c0) c1)])]
  283.     [(solve-poly ,x [,c0 ,c1 ,c2])
  284.      ; c + bx + ax^2 = 0
  285.      ; x = (-b +- sqrt(q)) / 2a
  286.      ;   q = b^2 - 4ac
  287.      (let* ([q (- (* c1 c1) (* 4 c2 c0))]
  288.             [solu (λ (sign)
  289.                     (/ (- (* sign (sqrt q)) c1)
  290.                        (+ c2 c2)))])
  291.        (cond
  292.          [(zero? q) `(solutions [,x ,(solu +1)])]
  293.          [else      `(solutions [,x ,(solu +1)]
  294.                                 [,x ,(solu -1)])]))]
  295.     [(solve-poly ,x [,c ...])
  296.      (error "cannot solve polynomial of degree > 2")]))
  297.  
  298.  
  299. ;==============
  300.  
  301. (define cas
  302.   (compose unparse-Asolution
  303.            solve
  304.            polynomial
  305.            one-variable
  306.            remove-zeros
  307.            merge-terms
  308.            simplify-terms
  309.            flat-trees
  310.            distribute
  311.            remove-negate
  312.            remove-subtract
  313.            rhs-zero
  314.            parse-sexp
  315.            parse-math))
  316.  
  317.  
  318. (module+ main
  319.  
  320.   (define (read+cas port)
  321.     (define ln (read-line port))
  322.     (cdr (cas (open-input-string ln))))
  323.  
  324.   (define (read/prompt prompt reader)
  325.     (λ (port)
  326.       (display prompt)
  327.       (flush-output)
  328.       (reader port)))
  329.  
  330.   (define (read/catch is-exn deflt reader)
  331.     (λ (port)
  332.       (with-handlers ([is-exn (λ (e)
  333.                                 (printf "; error: ~a\n" (exn-message e))
  334.                                 deflt)])
  335.         (reader port))))
  336.  
  337.   (define reader
  338.     (read/prompt "cas> "
  339.                  (read/catch exn:fail? '()
  340.                             read+cas)))
  341.  
  342.   (for* ([solus (in-port reader)]
  343.          [solu (in-list solus)])
  344.     (printf "~a = ~a\n"
  345.             (first solu)
  346.             (second solu)))
  347.   )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement