I am trying to implement a function
; (simplify expr)
;
; where expr is one of the following
; - a number
; - a symbol
; - a list of the form '(a operator b) where a and b are arithmetic expressions
The function is NOT supposed to simplify the arithmetic expression as far as possible, I just need it to simplify the subexpressions without variables:
examples:
(simplify '(3 + a)) => '(3 + a)
(simplify '(((2 + (3 * 4)) * a) + 2) => '((14 * a) + 2)
(simplify '((2 + (3 - a)) * 2) => '((2 + (3 - a)) * 2)
I already implemented a function that evaluates an arithmetic expression:
(define (eval t)
(cond
[(number? t) t]
[else ((cond
[(equal? (second t) '+) +]
[(equal? (second t) '-) -]
[(equal? (second t) '*) *]
[(equal? (second t) '/) /])
(eval (first t)) (eval (third t)))]))
This is what I have so far, but aside from the fact that it does not even work properly, I guess that there is a much better way.
(define (simplify t)
(cond
[(number? t) t]
[(equal? 'a (first t)) `(,(first t) ,(second t) ,(simplify (third t))) ]
[(equal? 'a (third t)) `(,(simplify (first t)) ,(second t) ,(third t)) ]
[else ((cond
[(equal? (second t) '+) +]
[(equal? (second t) '-) -]
[(equal? (second t) '*) *]
[(equal? (second t) '/) /])
(simplify (first t)) (simplify (third t)))]))
Any help is greatly appreciated!
The key insight is that
(number operation number)
can be simplified to
the result of evaluating (number operation number)
So add a clause in simplify that checks for the pattern (number operation number) then use your eval function to find the result.
Related
I have a function called clean-up which basically does what the already available flatten function does. I then have a function called multiplier, which takes in a list and multiplies all the numbers within it. The one issue is that sometimes there could be a weird syntax for the list used in multiplier, and it doesn't multiply every number together. For example:
Example Input
(multiplier '((1 (2 3)) 4 5 (6)))
Correct Output
720
My Output
*: contract violation
expected: number?
given: '(6 . 1)
argument position: 2nd
other arguments...
We don't like errors now do we? This multiplier function works in a normal-looking list, something like (multiplier '(1 2 3 4 5 6)). So I wrote the clean-up function to turn some confusing-looking list into a normal-looking list. However, I don't know how to call it to clean-up my list before trying to parse through and do the multiplication. I can verify that the clean-up function does its job perfectly. Can anyone help? Here is the code I have for both:
(define (clean-up s)
(cond [(null? s) '()]
[(not (pair? s)) (list s)]
[else (append (clean-up (car s)) (clean-up (cdr s)))]
))
(define multiplier
(lambda (s)
(cond [(null? s) 1]
[(number? (car s)) (* (car s) (multiplier(cdr s)))]
[list? (car s) (append (car s) (multiplier(cdr s)))]
[else (multiplier (cdr s))]
)))
There is no need for the clean-up function to solve the problems encountered in multiplier. However, you could call clean-up on the input first simply with:
scratch.rkt> (multiplier (clean-up '((1 (2 3)) 4 5 (6))))
720
Or, you could create a helper function to do this for you:
(define (multiplier-workaround s)
(multiplier (clean-up s)))
scratch.rkt> (multiplier-workaround '((1 (2 3)) 4 5 (6)))
720
A workaround like this might help you out in a pinch, but it does not fix the real problems in the code.
Some of the problems here may be easier to see with better code formatting. It is bad style to leave hanging parentheses in Lisps as if these are C-style languages; but that probably isn't causing you problems here. Yet it is good style to show the structure of your expressions using indentation. With proper indentation it becomes apparent that there are missing parentheses in the line with the list? predicate:
(define multiplier
(lambda (s)
(cond [(null? s) 1]
[(number? (car s))
(* (car s) (multiplier(cdr s)))]
[list? (car s)
(append (car s) (multiplier (cdr s)))]
[else
(multiplier (cdr s))])))
Further investigation of that line shows that the code is attempting to append (car s) to the result of (multiplier (cdr s)); yet, (car s) is now known to be a list, and multiplier is supposed to return a number! The intention here was surely to multiply the result of calling multiply on the list (car s) together with the result of (multiplier (cdr s)):
(define multiplier
(lambda (s)
(cond [(null? s) 1]
[(number? (car s))
(* (car s)
(multiplier (cdr s)))]
[(list? (car s))
(* (multiplier (car s))
(multiplier (cdr s)))]
[else
(multiplier (cdr s))])))
It isn't clear why the else branch is needed, unless OP wants to be able to process lists such as (a (1 (2 b) (3 (c (4 5) 6) d) e))). For code that is expecting nested lists of numbers, this would be fine:
(define multiplier-2
(lambda (s)
(cond [(null? s) 1]
[(number? (car s))
(* (car s) (multiplier (cdr s)))]
[else
(* (multiplier (car s))
(multiplier (cdr s)))])))
Both functions now work for OP example expression, and the corrected OP code also works for input with spurious values:
scratch.rkt> (multiplier '((1 (2 3)) 4 5 (6)))
720
scratch.rkt> (multiplier-2 '((1 (2 3)) 4 5 (6)))
720
scratch.rkt> (multiplier '(a (1 (2 3)) 4 5 b (6) c))
720
I think buildin flatten have more error handling.
(define (multiplier lst)
(apply * (filter number? (flatten lst))))
;;; TEST
(define test-lst1 (list + (vector 1) '(1 (2 3) c) "w" 4 5 '(6) + - * sqr))
(define test-lst2 '(1(a 2(3 b (c 4(d 5 e(6) (f)))))))
(multiplier test-lst1) ; 720
(multiplier test-lst2) ; 720
I've got an issue where I've got a macro, isentropic expansion which then calls solve-format replacing NIL in a list with 'x?, which then returns a valid expression can be passed to solve.
(isentropic-expansion 295 nil 1 4.2 1.4)
returns
(-
(expt
(/ 4.2 1)
(/
(- 1.4 1)
1.4))
(/ x\? 295))
which is the valid expression to then put into the solve function
but if I do the following (let's imagine I've set the output from the above command to the variable expr
(solve expr 2)
the macro doesn't replace the expression symbols with the value of expr, just expr the string, and I get
Wrong number of arguments: (lambda nil expr), 1
I think this is because I don't fully understand macros yet! Can anyone explain why this is please?
(defun newton-f (func x0)
"Solve the equation FUNC(x)=0 using Newton's method.
X0 is an initial guess."
(let* ((tolerance 1e-6)
(x x0)
(dx 1e-6)
fx fpx)
(while (> (abs (funcall func x)) tolerance)
(setq fx (funcall func x)
fpx (/ (- (funcall func (+ x dx)) (funcall func (- x dx))) (* 2 dx))
x (- x (/ fx fpx))))
x))
(defmacro solve (expression guess)
`(newton-f
(lambda ,(cl-loop for item in (flatten expression)
if (and (symbolp item) (s-ends-with? "?" (symbol-name item)))
collect item)
,expression)
,guess))
(defun solve-format (exp)
(cond ((null exp) 'x?)
((atom exp) exp)
((list exp) (cons (solve-format (car exp))
(if (cdr exp)
(solve-format (cdr exp))
nil)))
(t (print "what"))))
(defmacro isentropic-expansion (t01 t02 p01 p02 gamma)
`(solve-format '(- (expt (/ ,p02 ,p01) (/ (- ,gamma 1) ,gamma)) (/ ,t02 ,t01))))
solve is also a macro:
(defmacro solve (expression guess) ...)
As macros do not automatically evaluate their arguments, when you use this:
(solve expr 2)
During the macro's expansion it has expression bound to the symbol expr and guess bound to the number 2.
The (lambda nil expr) in the error message is this call:
(lambda ,(cl-loop for item in (flatten expression)
if (and (symbolp item) (s-ends-with? "?" (symbol-name item)))
collect item)
,expression)
I am new in Lisp and i need some help.
I need to simplify next expressions:
from (+ (+ A B) C) to (+ A B C)
and from (- (- A B) C) to (- A B C).
If you could help me with one of them I'll understand how i need to do this to the next one.
Thanks a lot.
Assuming you have an input that matches this pattern, (+ e1 ... en), you want to recursively simplify all e1 to en, which gives you s1, ..., sn, and then extract all the si that start with a + to move their arguments one level up, to the simplified expression you are building.
An expression e matches the above pattern if (and (consp e) (eq '+ (car e))).
Then, all the ei are just given by the list that is (cdr e).
Consider the (+) case, how could you simplify it?
To apply a function f to a list of values, call (mapcar #'f list).
To split a list into two lists, based on a predicate p, you might use a loop:
(let ((sat nil) (unsat nil))
(dolist (x list (values sat unsat))
(if (funcall predicate x)
(push x sat)
(push x unsat))))
There is a purely functional way to write this, can you figure it out?
Here is a trivial simplifier written in Racket, with an implementation of a rather mindless simplifier for +. Note that this is not intended as anything serious: it's just what I typed in when I was thinking about this question.
This uses Racket's pattern matching, probably in a naïve way, to do some of the work.
(define/match (simplify expression)
;; simplifier driver
(((cons op args))
;; An operator with some arguments
;; Note that this assumes that the arguments to operators are always
;; expressions to simplify, so the recursive level can be here
(simplify-op op (map simplify args)))
((expr)
;; anything else
expr))
(define op-table (make-hash))
(define-syntax-rule (define-op-simplifier (op args) form ...)
;; Define a simplifier for op with arguments args
(hash-set! op-table 'op (λ (args) form ...)))
(define (simplify-op op args)
;; Note the slightly arcane fallback: you need to wrap it in a thunk
;; so hash-ref does not try to call it.
((hash-ref op-table op (thunk (λ (args) (cons op args)))) args))
(define-op-simplifier (+ exprs)
;; Simplify (+ ...) by flattening + in its arguments
(let loop ([ftail exprs]
[results '()])
(if (null? ftail)
`(+ ,#(reverse results))
(loop (rest ftail)
(match (first ftail)
[(cons '+ addends)
(append (reverse addends) results)]
[expr (cons expr results)])))))
It is possible to be more aggressive than this. For instance we can coalesce runs of literal numbers, so we can simplify (+ 1 2 3 a 4) to
(+ 6 a 4) (note it is not safe in general to further simplify this to (+ 10 a) unless all arithmetic is exact). Here is a function which does this coalescing for for + and *:
(define (coalesce-literal-numbers f elts)
;; coalesce runs of literal numbers for an operator f.
;; This relies on the fact that (f) returns a good identity for f
;; (so in particular it returns an exact number). Thisis true for Racket
;; and CL and I think any Lisp worth its salt.
;;
;; Note that it's important here that (eqv? 1 1.0) is false.
;;;
(define id (f))
(let loop ([tail elts]
[accum id]
[results '()])
(cond [(null? tail)
(if (not (eqv? accum id))
(reverse (cons accum results))
(reverse results))]
[(number? (first tail))
(loop (rest tail)
(f accum (first tail))
results)]
[(eqv? accum id)
(loop (rest tail)
accum
(cons (first tail) results))]
[else
(loop (rest tail)
id
(list* (first tail) accum results))])))
And here is a modified simplifier for + which uses this. As well as coalescing it notices that (+ x) can be simplified to x.
(define-op-simplifier (+ exprs)
;; Simplify (+ ...) by flattening + in its arguments
(let loop ([ftail exprs]
[results '()])
(if (null? ftail)
(let ([coalesced (coalesce-literal-numbers + (reverse results))])
(match coalesced
[(list something)
something]
[exprs
`(+ ,#exprs)]))
(loop (rest ftail)
(match (first ftail)
[(cons '+ addends)
(append (reverse addends) results)]
[expr (cons expr results)])))))
Here is an example of using this enhanced simplifier:
> (simplify 'a)
'a
> (simplify 1)
1
> (simplify '(+ 1 a))
'(+ 1 a)
> (simplify '(+ a (+ b c)))
'(+ a b c)
> (simplify '(+ 1 (+ 3 c) 4))
'(+ 4 c 4)
> (simplify '(+ 1 2 3))
6
For yet more value you can notice that the simplifier for * is really the same, and change things to this:
(define (simplify-arith-op op fn exprs)
(let loop ([ftail exprs]
[results '()])
(if (null? ftail)
(let ([coalesced (coalesce-literal-numbers fn (reverse results))])
(match coalesced
[(list something)
something]
['()
(fn)]
[exprs
`(,op ,#exprs)]))
(loop (rest ftail)
(match (first ftail)
[(cons the-op addends)
#:when (eqv? the-op op)
(append (reverse addends) results)]
[expr (cons expr results)])))))
(define-op-simplifier (+ exprs)
(simplify-arith-op '+ + exprs))
(define-op-simplifier (* exprs)
(simplify-arith-op '* * exprs))
And now
(simplify '(+ a (* 1 2 (+ 4 5)) (* 3 4) 6 (* b)))
'(+ a 36 b)
Which is reasonably neat.
You can go further than this, For instance when coalescing numbers for an operator you can simply elide sequences of the identity for that operator: (* 1 1 a 1 1 b) can be simplified to (* a b), not (* 1 a 1 b). It may seem silly to do that: who would ever write such an expression, but they can quite easily occur when simplifying complicated expressions.
There is a gist of an elaborated version of this code. It may still be buggy.
I have to write a simple program in Lisp that multiplies a polynomial by some factor. In this example, I want to multiply (x + 5) * 5x. The answer should be 5x^2 + 25x.
When I put in ((1 1) (5 0)) (5 1)) I should get (5 2) (25 1). However, I'm getting various errors ranging from undefined operator TERM in (TERM) and bad binding form. I'm a novice at Lisp and trying to return a list as shown above. Below is my short block of code:
(defun get-coef (term)
(car term))
(defun get-power (term)
(cadr term))
(defun make-term (coef power)
(cons coef power))
(defun poly-eval (poly factor)
(if (null poly) 0
(let ((term (car poly))
(let (coef ((* (get-coef(term)) (get-coef(factor)))))
(power ((+ (cadr(term)) (cadr(factor)))))
(make-term (coef power))
(poly-eval (cdr poly) factor))))))
Any help is appreciated!!
Several problems with your code:
You are using (fun (arg1 arg2)) syntax. It should be (fun arg1 arg2). For example, you write (make-term (coef power)) but it should be (make-term coef power).
Your bindings in let are all over the place. The correct syntax is
(let ((v1 e1)
(v2 e2)
(v3 e3))
e0)
i.e. all the bindings are in one list, and each binding is a list of two elements. Note that the expressions that the variables are bound to (e1 etc.) are not wrapped in any extra layers of parentheses.
make-term doesn't use the same representation as get-power. In get-power you use cadr so you need to make sure make-term puts the power in the right position.
Your poly-eval doesn't actually combine (make-term coef power) with the recursive call to (poly-eval (cdr poly) factor), so it gets lost. You should cons the "here"-result to the "there"-result.
Your poly-eval returns 0 instead of the empty list for empty polynomials.
All in all, your code can be fixed as
(defun get-coef (term)
(car term))
(defun get-power (term)
(cadr term))
(defun make-term (coef power)
(list coef power))
(defun poly-eval (poly factor)
(if (null poly) nil
(let ((term (car poly)))
(let
((coef (* (get-coef term) (get-coef factor)))
(power (+ (get-power term) (get-power factor))))
(cons (make-term coef power)
(poly-eval (cdr poly) factor))))))
giving e.g.
(poly-eval '((1 1) (5 0)) '(5 1))
resulting in
((5 2) (25 1))
Your make-term uses CONS but your get-power takes the CADR:
(defun get-power (term) (cadr term))
(defun make-term (coef power) (cons coef power))
You prolly wanted (list coef power).
(cons 'c 'p) returns (c . p), not (c p).
Now your get-power goes for CADR, the CAR of the CDR, but the CDR is 'p.
Your inputs are lists of coeff and power eg (5 1), so it seems the only problem is in your make-term.
Or you can turn around and be consistent with (( 5 . 1)(5 . 0) and then change get power to be (cdr term).
Another way:
(defun mult(term factor)
(list (* (first term) (first factor)) (+ (second term) (second factor))))
(defun polyeval(poly factor)
(cond
((null poly) nil)
(t (cons (mult (first poly) factor) (polyeval (rest poly) factor)))))
Note: first=car, rest=cdr, second=cadr
I'm new to Lisp and I'm working through some tutorials. Below is the given code for differentiating polynomials. I want to streamline it so (d) and (simplify) are one function / can be done in one step. I was thinking something (defun differentiate (poly x) (simplify (d (poly x)))) but then it thinks poly is a function, which doesn't work.
Maybe this doesn't work because the input for (d) has to be quoted? i.e. (d '(+ x y) 'x)
Sorry for the large chunk of code but I thought it would be best to put it all in. The relevant functions are at the bottom.
;;
;; Constructors for polynomials
;;
(defun make-constant (num)
num)
(defun make-variable (sym)
sym)
(defun make-negation (poly)
(list '- poly))
(defun make-sum (poly1 poly2)
(list '+ poly1 poly2))
(defun make-difference (poly1 poly2)
(list '- poly1 poly2))
(defun make-product (poly1 poly2)
(list '* poly1 poly2))
(defun make-power (poly num)
(list '** poly num))
;;
;; Recognizers for polynomials
;;
(defun constant-p (poly)
(numberp poly))
(defun variable-p (poly)
(symbolp poly))
(defun negation-p (poly)
(and (listp poly) (eq (first poly) '-) (null (rest (rest poly)))))
(defun sum-p (poly)
(and (listp poly) (eq (first poly) '+)))
(defun difference-p (poly)
(and (listp poly) (eq (first poly) '-) (not (null (rest (rest poly))))))
(defun product-p (poly)
(and (listp poly) (eq (first poly) '*)))
(defun power-p (poly)
(and (listp poly) (eq (first poly) '**)))
;;
;; Selectors for polynomials
;;
(defun constant-numeric (const)
const)
(defun variable-symbol (var)
var)
(defun negation-arg (neg)
(second neg))
(defun sum-arg1 (sum)
(second sum))
(defun sum-arg2 (sum)
(third sum))
(defun difference-arg1 (diff)
(second diff))
(defun difference-arg2 (diff)
(third diff))
(defun product-arg1 (prod)
(second prod))
(defun product-arg2 (prod)
(third prod))
(defun power-base (pow)
(second pow))
(defun power-exponent (pow)
(third pow))
;;
;; Unevaluated derivative
;;
(defun make-derivative (poly x)
(list 'd poly x))
(defun derivative-p (poly)
(and (listp poly) (eq (first poly) 'd)))
;;
;; Differentiation function
;;
(defun d (poly x)
(cond
((constant-p poly) 0)
((variable-p poly)
(if (equal poly x)
1
(make-derivative poly x)))
((negation-p poly)
(make-negation (d (negation-arg poly) x)))
((sum-p poly)
(make-sum (d (sum-arg1 poly) x)
(d (sum-arg2 poly) x)))
((difference-p poly)
(make-difference (d (difference-arg1 poly) x)
(d (difference-arg2 poly) x)))
((product-p poly)
(make-sum (make-product (product-arg1 poly)
(d (product-arg2 poly) x))
(make-product (product-arg2 poly)
(d (product-arg1 poly) x))))
((power-p poly)
(make-product (make-product (power-exponent poly)
(make-power (power-base poly)
(1- (power-exponent poly))))
(d (power-base poly) x)))))
;;
;; Simplification function
;;
(defun simplify (poly)
"Simplify polynomial POLY."
(cond
((constant-p poly) poly)
((variable-p poly) poly)
((negation-p poly)
(let ((arg (simplify (negation-arg poly))))
(make-simplified-negation arg)))
((sum-p poly)
(let ((arg1 (simplify (sum-arg1 poly)))
(arg2 (simplify (sum-arg2 poly))))
(make-simplified-sum arg1 arg2)))
((product-p poly)
(let ((arg1 (simplify (product-arg1 poly)))
(arg2 (simplify (product-arg2 poly))))
(make-simplified-product arg1 arg2)))
((difference-p poly)
(let ((arg1 (simplify (difference-arg1 poly)))
(arg2 (simplify (difference-arg2 poly))))
(make-simplified-difference arg1 arg2)))
((power-p poly)
(let ((base (simplify (power-base poly)))
(exponent (simplify (power-exponent poly))))
(make-simplified-power base exponent)))
((derivative-p poly) poly)))
(defun make-simplified-negation (arg)
"Given simplified polynomial ARG, construct a simplified negation of ARG."
(cond
((and (constant-p arg) (zerop arg)) arg)
((negation-p arg) (negation-arg arg))
(t (make-negation arg))))
(defun make-simplified-sum (arg1 arg2)
"Given simplified polynomials ARG1 and ARG2, construct a simplified sum of ARG1 and ARG2."
(cond
((and (constant-p arg1) (zerop arg1)) arg2)
((and (constant-p arg2) (zerop arg2)) arg1)
((negation-p arg1) (make-simplified-difference
arg2 (negation-arg arg1)))
((negation-p arg2) (make-simplified-difference
arg1 (negation-arg arg2)))
(t (make-sum arg1 arg2))))
(defun make-simplified-difference (arg1 arg2)
"Given simplified polynomials ARG1 and ARG2, construct a simplified difference of ARG1 and ARG2."
(cond
((and (constant-p arg2) (zerop arg2)) arg1)
((and (constant-p arg1) (zerop arg1)) (make-simplified-negation arg2))
((negation-p arg2) (make-simplified-sum
arg1 (negation-arg arg2)))
(t (make-difference arg1 arg2))))
(defun make-simplified-product (arg1 arg2)
"Given simplified polynomials ARG1 and ARG2, construct a simplified product of ARG1 and ARG2."
(cond
((and (constant-p arg1) (zerop arg1)) (make-constant 0))
((and (constant-p arg2) (zerop arg2)) (make-constant 0))
((and (constant-p arg1) (= arg1 1)) arg2)
((and (constant-p arg2) (= arg2 1)) arg1)
((and (constant-p arg1) (= arg1 -1)) (make-simplified-negation arg2))
((and (constant-p arg2) (= arg2 -1)) (make-simplified-negation arg1))
(t (make-product arg1 arg2))))
(defun make-simplified-power (base exponent)
"Given simplified polynomials BASE and EXPONENT, construct a simplified power with base BASE and exponent EXPONENT."
(cond
((and (constant-p exponent) (= exponent 1)) base)
((and (constant-p exponent) (zerop exponent)) (make-constant 1))
(t (make-power base exponent))))
The inputs to poly don't "need to be quoted". Instead of
(d '(+ x y) 'x)
you could write any of the following:
(d (list '+ 'x 'y) 'x)
(d (make-sum 'x 'y) 'x)
(let ((ex 'x) (why 'y))
(d (list '+ ex why) ex))
In your attempt in the question, you're trying to call d with the result of (poly x) which tries to call a function a named poly (actually, the function binding of the symbol poly, or some other possible things, but that's probably more in-depth than we need to get right now) with the value of the variable x:
(defun differentiate (poly x)
;; call poly with the value of x to produce a value y, and
;; then call d with y to produce a value z, and then call
;; simplify with z.
(simplify (d (poly x))))
That won't work, of course, because there's no function named poly, and even if there was, d expects two arguments, not one. Instead, the first thing you should do is call d with two arguments, viz., the values of the variables poly and x, and then call simplify with the result of that:
(defun differentiate (poly x)
(simplify (d poly x)))